Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/ExpressionParser/Clang/ClangASTImporter.h
Line
Count
Source (jump to first uncovered line)
1
//===-- ClangASTImporter.h --------------------------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#ifndef LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
10
#define LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H
11
12
#include <map>
13
#include <memory>
14
#include <set>
15
#include <vector>
16
17
#include "clang/AST/ASTImporter.h"
18
#include "clang/AST/CharUnits.h"
19
#include "clang/AST/Decl.h"
20
#include "clang/AST/DeclCXX.h"
21
#include "clang/Basic/FileManager.h"
22
#include "clang/Basic/FileSystemOptions.h"
23
24
#include "lldb/Host/FileSystem.h"
25
#include "lldb/Symbol/CompilerDeclContext.h"
26
#include "lldb/Utility/LLDBAssert.h"
27
#include "lldb/lldb-types.h"
28
29
#include "Plugins/ExpressionParser/Clang/CxxModuleHandler.h"
30
31
#include "llvm/ADT/DenseMap.h"
32
33
namespace lldb_private {
34
35
class ClangASTMetadata;
36
class TypeSystemClang;
37
38
/// Manages and observes all Clang AST node importing in LLDB.
39
///
40
/// The ClangASTImporter takes care of two things:
41
///
42
/// 1. Keeps track of all ASTImporter instances in LLDB.
43
///
44
/// Clang's ASTImporter takes care of importing types from one ASTContext to
45
/// another. This class expands this concept by allowing copying from several
46
/// ASTContext instances to several other ASTContext instances. Instead of
47
/// constructing a new ASTImporter manually to copy over a type/decl, this class
48
/// can be asked to do this. It will construct a ASTImporter for the caller (and
49
/// will cache the ASTImporter instance for later use) and then perform the
50
/// import.
51
///
52
/// This mainly prevents that a caller might construct several ASTImporter
53
/// instances for the same source/target ASTContext combination. As the
54
/// ASTImporter has an internal state that keeps track of already imported
55
/// declarations and so on, using only one ASTImporter instance is more
56
/// efficient and less error-prone than using multiple.
57
///
58
/// 2. Keeps track of from where declarations were imported (origin-tracking).
59
/// The ASTImporter instances in this class usually only performa a minimal
60
/// import, i.e., only a shallow copy is made that is filled out on demand
61
/// when more information is requested later on. This requires record-keeping
62
/// of where any shallow clone originally came from so that the right original
63
/// declaration can be found and used as the source of any missing information.
64
class ClangASTImporter {
65
public:
66
  struct LayoutInfo {
67
8.13k
    LayoutInfo() = default;
68
    typedef llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
69
        OffsetMap;
70
71
    uint64_t bit_size = 0;
72
    uint64_t alignment = 0;
73
    llvm::DenseMap<const clang::FieldDecl *, uint64_t> field_offsets;
74
    OffsetMap base_offsets;
75
    OffsetMap vbase_offsets;
76
  };
77
78
  ClangASTImporter()
79
      : m_file_manager(clang::FileSystemOptions(),
80
4.25k
                       FileSystem::Instance().GetVirtualFileSystem()) {}
81
82
  /// Copies the given type and the respective declarations to the destination
83
  /// type system.
84
  ///
85
  /// This function does a shallow copy and requires that the target AST
86
  /// has an ExternalASTSource which queries this ClangASTImporter instance
87
  /// for any additional information that is maybe lacking in the shallow copy.
88
  /// This also means that the type system of src_type can *not* be deleted
89
  /// after this function has been called. If you need to delete the source
90
  /// type system you either need to delete the destination type system first
91
  /// or use \ref ClangASTImporter::DeportType.
92
  ///
93
  /// \see ClangASTImporter::DeportType
94
  CompilerType CopyType(TypeSystemClang &dst, const CompilerType &src_type);
95
96
  /// \see ClangASTImporter::CopyType
97
  clang::Decl *CopyDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
98
99
  /// Copies the given type and the respective declarations to the destination
100
  /// type system.
101
  ///
102
  /// Unlike CopyType this function ensures that types/declarations which are
103
  /// originally from the AST of src_type are fully copied over. The type
104
  /// system of src_type can safely be deleted after calling this function.
105
  /// \see ClangASTImporter::CopyType
106
  CompilerType DeportType(TypeSystemClang &dst, const CompilerType &src_type);
107
108
  /// Copies the given decl to the destination type system.
109
  /// \see ClangASTImporter::DeportType
110
  clang::Decl *DeportDecl(clang::ASTContext *dst_ctx, clang::Decl *decl);
111
112
  /// Sets the layout for the given RecordDecl. The layout will later be
113
  /// used by Clang's during code generation. Not calling this function for
114
  /// a RecordDecl will cause that Clang's codegen tries to layout the
115
  /// record by itself.
116
  ///
117
  /// \param decl The RecordDecl to set the layout for.
118
  /// \param layout The layout for the record.
119
  void SetRecordLayout(clang::RecordDecl *decl, const LayoutInfo &layout);
120
121
  bool LayoutRecordType(
122
      const clang::RecordDecl *record_decl, uint64_t &bit_size,
123
      uint64_t &alignment,
124
      llvm::DenseMap<const clang::FieldDecl *, uint64_t> &field_offsets,
125
      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
126
          &base_offsets,
127
      llvm::DenseMap<const clang::CXXRecordDecl *, clang::CharUnits>
128
          &vbase_offsets);
129
130
  /// Returns true iff the given type was copied from another TypeSystemClang
131
  /// and the original type in this other TypeSystemClang might contain
132
  /// additional information (e.g., the definition of a 'class' type) that could
133
  /// be imported.
134
  ///
135
  /// \see ClangASTImporter::Import
136
  bool CanImport(const CompilerType &type);
137
138
  /// If the given type was copied from another TypeSystemClang then copy over
139
  /// all missing information (e.g., the definition of a 'class' type).
140
  ///
141
  /// \return True iff an original type in another TypeSystemClang was found.
142
  ///         Note: Does *not* return false if an original type was found but
143
  ///               no information was imported over.
144
  ///
145
  /// \see ClangASTImporter::Import
146
  bool Import(const CompilerType &type);
147
148
  bool CompleteType(const CompilerType &compiler_type);
149
150
  bool CompleteTagDecl(clang::TagDecl *decl);
151
152
  bool CompleteTagDeclWithOrigin(clang::TagDecl *decl, clang::TagDecl *origin);
153
154
  bool CompleteObjCInterfaceDecl(clang::ObjCInterfaceDecl *interface_decl);
155
156
  bool CompleteAndFetchChildren(clang::QualType type);
157
158
  bool RequireCompleteType(clang::QualType type);
159
160
  /// Updates the internal origin-tracking information so that the given
161
  /// 'original' decl is from now on used to import additional information
162
  /// into the given decl.
163
  ///
164
  /// Usually the origin-tracking in the ClangASTImporter is automatically
165
  /// updated when a declaration is imported, so the only valid reason to ever
166
  /// call this is if there is a 'better' original decl and the target decl
167
  /// is only a shallow clone that lacks any contents.
168
  void SetDeclOrigin(const clang::Decl *decl, clang::Decl *original_decl);
169
170
  ClangASTMetadata *GetDeclMetadata(const clang::Decl *decl);
171
172
  //
173
  // Namespace maps
174
  //
175
176
  typedef std::pair<lldb::ModuleSP, CompilerDeclContext> NamespaceMapItem;
177
  typedef std::vector<NamespaceMapItem> NamespaceMap;
178
  typedef std::shared_ptr<NamespaceMap> NamespaceMapSP;
179
180
  void RegisterNamespaceMap(const clang::NamespaceDecl *decl,
181
                            NamespaceMapSP &namespace_map);
182
183
  NamespaceMapSP GetNamespaceMap(const clang::NamespaceDecl *decl);
184
185
  void BuildNamespaceMap(const clang::NamespaceDecl *decl);
186
187
  //
188
  // Completers for maps
189
  //
190
191
  class MapCompleter {
192
  public:
193
    virtual ~MapCompleter();
194
195
    virtual void CompleteNamespaceMap(NamespaceMapSP &namespace_map,
196
                                      ConstString name,
197
                                      NamespaceMapSP &parent_map) const = 0;
198
  };
199
200
  void InstallMapCompleter(clang::ASTContext *dst_ctx,
201
15.3k
                           MapCompleter &completer) {
202
15.3k
    ASTContextMetadataSP context_md;
203
15.3k
    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
204
205
15.3k
    if (context_md_iter == m_metadata_map.end()) {
206
15.3k
      context_md = ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
207
15.3k
      m_metadata_map[dst_ctx] = context_md;
208
15.3k
    } else {
209
0
      context_md = context_md_iter->second;
210
0
    }
211
212
15.3k
    context_md->m_map_completer = &completer;
213
15.3k
  }
214
215
  void ForgetDestination(clang::ASTContext *dst_ctx);
216
  void ForgetSource(clang::ASTContext *dst_ctx, clang::ASTContext *src_ctx);
217
218
  struct DeclOrigin {
219
17.1M
    DeclOrigin() = default;
220
221
    DeclOrigin(clang::ASTContext *_ctx, clang::Decl *_decl)
222
2.62M
        : ctx(_ctx), decl(_decl) {
223
      // The decl has to be in its associated ASTContext.
224
2.62M
      assert(_decl == nullptr || &_decl->getASTContext() == _ctx);
225
2.62M
    }
226
227
4.93M
    DeclOrigin(const DeclOrigin &rhs) {
228
4.93M
      ctx = rhs.ctx;
229
4.93M
      decl = rhs.decl;
230
4.93M
    }
231
232
2.63M
    void operator=(const DeclOrigin &rhs) {
233
2.63M
      ctx = rhs.ctx;
234
2.63M
      decl = rhs.decl;
235
2.63M
    }
236
237
16.9M
    bool Valid() const { return (ctx != nullptr || 
decl != nullptr16.5M
); }
238
239
    clang::ASTContext *ctx = nullptr;
240
    clang::Decl *decl = nullptr;
241
  };
242
243
  /// Listener interface used by the ASTImporterDelegate to inform other code
244
  /// about decls that have been imported the first time.
245
  struct NewDeclListener {
246
8.88k
    virtual ~NewDeclListener() = default;
247
    /// A decl has been imported for the first time.
248
    virtual void NewDeclImported(clang::Decl *from, clang::Decl *to) = 0;
249
  };
250
251
  /// ASTImporter that intercepts and records the import process of the
252
  /// underlying ASTImporter.
253
  ///
254
  /// This class updates the map from declarations to their original
255
  /// declarations and can record declarations that have been imported in a
256
  /// certain interval.
257
  ///
258
  /// When intercepting a declaration import, the ASTImporterDelegate uses the
259
  /// CxxModuleHandler to replace any missing or malformed declarations with
260
  /// their counterpart from a C++ module.
261
  struct ASTImporterDelegate : public clang::ASTImporter {
262
    ASTImporterDelegate(ClangASTImporter &main, clang::ASTContext *target_ctx,
263
                        clang::ASTContext *source_ctx)
264
        : clang::ASTImporter(*target_ctx, main.m_file_manager, *source_ctx,
265
                             main.m_file_manager, true /*minimal*/),
266
18.7k
          m_main(main), m_source_ctx(source_ctx) {
267
      // Target and source ASTContext shouldn't be identical. Importing AST
268
      // nodes within the same AST doesn't make any sense as the whole idea
269
      // is to import them to a different AST.
270
18.7k
      lldbassert(target_ctx != source_ctx && "Can't import into itself");
271
      // This is always doing a minimal import of any declarations. This means
272
      // that there has to be an ExternalASTSource in the target ASTContext
273
      // (that should implement the callbacks that complete any declarations
274
      // on demand). Without an ExternalASTSource, this ASTImporter will just
275
      // do a minimal import and the imported declarations won't be completed.
276
18.7k
      assert(target_ctx->getExternalSource() && "Missing ExternalSource");
277
0
      setODRHandling(clang::ASTImporter::ODRHandlingType::Liberal);
278
18.7k
    }
279
280
    /// Scope guard that attaches a CxxModuleHandler to an ASTImporterDelegate
281
    /// and deattaches it at the end of the scope. Supports being used multiple
282
    /// times on the same ASTImporterDelegate instance in nested scopes.
283
    class CxxModuleScope {
284
      /// The handler we attach to the ASTImporterDelegate.
285
      CxxModuleHandler m_handler;
286
      /// The ASTImporterDelegate we are supposed to attach the handler to.
287
      ASTImporterDelegate &m_delegate;
288
      /// True iff we attached the handler to the ASTImporterDelegate.
289
      bool m_valid = false;
290
291
    public:
292
      CxxModuleScope(ASTImporterDelegate &delegate, clang::ASTContext *dst_ctx)
293
875k
          : m_delegate(delegate) {
294
        // If the delegate doesn't have a CxxModuleHandler yet, create one
295
        // and attach it.
296
875k
        if (!delegate.m_std_handler) {
297
351k
          m_handler = CxxModuleHandler(delegate, dst_ctx);
298
351k
          m_valid = true;
299
351k
          delegate.m_std_handler = &m_handler;
300
351k
        }
301
875k
      }
302
875k
      ~CxxModuleScope() {
303
875k
        if (m_valid) {
304
          // Make sure no one messed with the handler we placed.
305
351k
          assert(m_delegate.m_std_handler == &m_handler);
306
0
          m_delegate.m_std_handler = nullptr;
307
351k
        }
308
875k
      }
309
    };
310
311
    void ImportDefinitionTo(clang::Decl *to, clang::Decl *from);
312
313
    void Imported(clang::Decl *from, clang::Decl *to) override;
314
315
    clang::Decl *GetOriginalDecl(clang::Decl *To) override;
316
317
8.88k
    void SetImportListener(NewDeclListener *listener) {
318
8.88k
      assert(m_new_decl_listener == nullptr && "Already attached a listener?");
319
0
      m_new_decl_listener = listener;
320
8.88k
    }
321
8.88k
    void RemoveImportListener() { m_new_decl_listener = nullptr; }
322
323
  protected:
324
    llvm::Expected<clang::Decl *> ImportImpl(clang::Decl *From) override;
325
326
  private:
327
    /// Decls we should ignore when mapping decls back to their original
328
    /// ASTContext. Used by the CxxModuleHandler to mark declarations that
329
    /// were created from the 'std' C++ module to prevent that the Importer
330
    /// tries to sync them with the broken equivalent in the debug info AST.
331
    llvm::SmallPtrSet<clang::Decl *, 16> m_decls_to_ignore;
332
    ClangASTImporter &m_main;
333
    clang::ASTContext *m_source_ctx;
334
    CxxModuleHandler *m_std_handler = nullptr;
335
    /// The currently attached listener.
336
    NewDeclListener *m_new_decl_listener = nullptr;
337
  };
338
339
  typedef std::shared_ptr<ASTImporterDelegate> ImporterDelegateSP;
340
  typedef llvm::DenseMap<clang::ASTContext *, ImporterDelegateSP> DelegateMap;
341
  typedef llvm::DenseMap<const clang::NamespaceDecl *, NamespaceMapSP>
342
      NamespaceMetaMap;
343
344
  class ASTContextMetadata {
345
    typedef llvm::DenseMap<const clang::Decl *, DeclOrigin> OriginMap;
346
347
  public:
348
18.0k
    ASTContextMetadata(clang::ASTContext *dst_ctx) : m_dst_ctx(dst_ctx) {}
349
350
    clang::ASTContext *m_dst_ctx;
351
    DelegateMap m_delegates;
352
353
    NamespaceMetaMap m_namespace_maps;
354
    MapCompleter *m_map_completer = nullptr;
355
356
    /// Sets the DeclOrigin for the given Decl and overwrites any existing
357
    /// DeclOrigin.
358
2.63M
    void setOrigin(const clang::Decl *decl, DeclOrigin origin) {
359
      // Setting the origin of any decl to itself (or to a different decl
360
      // in the same ASTContext) doesn't make any sense. It will also cause
361
      // ASTImporterDelegate::ImportImpl to infinite recurse when trying to find
362
      // the 'original' Decl when importing code.
363
2.63M
      assert(&decl->getASTContext() != origin.ctx &&
364
2.63M
             "Trying to set decl origin to its own ASTContext?");
365
0
      assert(decl != origin.decl && "Trying to set decl origin to itself?");
366
0
      m_origins[decl] = origin;
367
2.63M
    }
368
369
    /// Removes any tracked DeclOrigin for the given decl.
370
66.5k
    void removeOrigin(const clang::Decl *decl) { m_origins.erase(decl); }
371
372
    /// Remove all DeclOrigin entries that point to the given ASTContext.
373
    /// Useful when an ASTContext is about to be deleted and all the dangling
374
    /// pointers to it need to be removed.
375
13.7k
    void removeOriginsWithContext(clang::ASTContext *ctx) {
376
13.7k
      for (OriginMap::iterator iter = m_origins.begin();
377
2.54M
           iter != m_origins.end();) {
378
2.53M
        if (iter->second.ctx == ctx)
379
1.64M
          m_origins.erase(iter++);
380
883k
        else
381
883k
          ++iter;
382
2.53M
      }
383
13.7k
    }
384
385
    /// Returns the DeclOrigin for the given Decl or an invalid DeclOrigin
386
    /// instance if there no known DeclOrigin for the given Decl.
387
16.3M
    DeclOrigin getOrigin(const clang::Decl *decl) const {
388
16.3M
      auto iter = m_origins.find(decl);
389
16.3M
      if (iter == m_origins.end())
390
14.5M
        return DeclOrigin();
391
1.74M
      return iter->second;
392
16.3M
    }
393
394
    /// Returns true there is a known DeclOrigin for the given Decl.
395
2.84M
    bool hasOrigin(const clang::Decl *decl) const {
396
2.84M
      return getOrigin(decl).Valid();
397
2.84M
    }
398
399
  private:
400
    /// Maps declarations to the ASTContext/Decl from which they were imported
401
    /// from. If a declaration is from an ASTContext which has been deleted
402
    /// since the declaration was imported or the declaration wasn't created by
403
    /// the ASTImporter, then it doesn't have a DeclOrigin and will not be
404
    /// tracked here.
405
    OriginMap m_origins;
406
  };
407
408
  typedef std::shared_ptr<ASTContextMetadata> ASTContextMetadataSP;
409
  typedef llvm::DenseMap<const clang::ASTContext *, ASTContextMetadataSP>
410
      ContextMetadataMap;
411
412
  ContextMetadataMap m_metadata_map;
413
414
14.3M
  ASTContextMetadataSP GetContextMetadata(clang::ASTContext *dst_ctx) {
415
14.3M
    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
416
417
14.3M
    if (context_md_iter == m_metadata_map.end()) {
418
2.71k
      ASTContextMetadataSP context_md =
419
2.71k
          ASTContextMetadataSP(new ASTContextMetadata(dst_ctx));
420
2.71k
      m_metadata_map[dst_ctx] = context_md;
421
2.71k
      return context_md;
422
2.71k
    }
423
14.3M
    return context_md_iter->second;
424
14.3M
  }
425
426
2.79M
  ASTContextMetadataSP MaybeGetContextMetadata(clang::ASTContext *dst_ctx) {
427
2.79M
    ContextMetadataMap::iterator context_md_iter = m_metadata_map.find(dst_ctx);
428
429
2.79M
    if (context_md_iter != m_metadata_map.end())
430
2.79M
      return context_md_iter->second;
431
0
    return ASTContextMetadataSP();
432
2.79M
  }
433
434
  ImporterDelegateSP GetDelegate(clang::ASTContext *dst_ctx,
435
889k
                                 clang::ASTContext *src_ctx) {
436
889k
    ASTContextMetadataSP context_md = GetContextMetadata(dst_ctx);
437
438
889k
    DelegateMap &delegates = context_md->m_delegates;
439
889k
    DelegateMap::iterator delegate_iter = delegates.find(src_ctx);
440
441
889k
    if (delegate_iter == delegates.end()) {
442
18.7k
      ImporterDelegateSP delegate =
443
18.7k
          ImporterDelegateSP(new ASTImporterDelegate(*this, dst_ctx, src_ctx));
444
18.7k
      delegates[src_ctx] = delegate;
445
18.7k
      return delegate;
446
18.7k
    }
447
870k
    return delegate_iter->second;
448
889k
  }
449
450
  DeclOrigin GetDeclOrigin(const clang::Decl *decl);
451
452
  clang::FileManager m_file_manager;
453
  typedef llvm::DenseMap<const clang::RecordDecl *, LayoutInfo>
454
      RecordDeclToLayoutMap;
455
456
  RecordDeclToLayoutMap m_record_decl_to_layout_map;
457
};
458
459
} // namespace lldb_private
460
461
#endif // LLDB_SOURCE_PLUGINS_EXPRESSIONPARSER_CLANG_CLANGASTIMPORTER_H