1 | //===- ASTImporter.h - Importing ASTs from other Contexts -------*- 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 | // This file defines the ASTImporter class which imports AST nodes from one |
10 | // context into another context. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_CLANG_AST_ASTIMPORTER_H |
15 | #define LLVM_CLANG_AST_ASTIMPORTER_H |
16 | |
17 | #include "clang/AST/ASTImportError.h" |
18 | #include "clang/AST/DeclBase.h" |
19 | #include "clang/AST/DeclarationName.h" |
20 | #include "clang/AST/ExprCXX.h" |
21 | #include "clang/AST/NestedNameSpecifier.h" |
22 | #include "clang/AST/TemplateName.h" |
23 | #include "clang/AST/Type.h" |
24 | #include "clang/Basic/Diagnostic.h" |
25 | #include "clang/Basic/IdentifierTable.h" |
26 | #include "clang/Basic/LLVM.h" |
27 | #include "clang/Basic/SourceLocation.h" |
28 | #include "llvm/ADT/DenseMap.h" |
29 | #include "llvm/ADT/DenseSet.h" |
30 | #include "llvm/ADT/SmallVector.h" |
31 | #include <optional> |
32 | #include <utility> |
33 | |
34 | namespace clang { |
35 | |
36 | class ASTContext; |
37 | class ASTImporterSharedState; |
38 | class Attr; |
39 | class CXXBaseSpecifier; |
40 | class CXXCtorInitializer; |
41 | class Decl; |
42 | class DeclContext; |
43 | class Expr; |
44 | class FileManager; |
45 | class NamedDecl; |
46 | class Stmt; |
47 | class TagDecl; |
48 | class TranslationUnitDecl; |
49 | class TypeSourceInfo; |
50 | |
51 | // \brief Returns with a list of declarations started from the canonical decl |
52 | // then followed by subsequent decls in the translation unit. |
53 | // This gives a canonical list for each entry in the redecl chain. |
54 | // `Decl::redecls()` gives a list of decls which always start from the |
55 | // previous decl and the next item is actually the previous item in the order |
56 | // of source locations. Thus, `Decl::redecls()` gives different lists for |
57 | // the different entries in a given redecl chain. |
58 | llvm::SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D); |
59 | |
60 | /// Imports selected nodes from one AST context into another context, |
61 | /// merging AST nodes where appropriate. |
62 | class ASTImporter { |
63 | friend class ASTNodeImporter; |
64 | public: |
65 | using NonEquivalentDeclSet = llvm::DenseSet<std::pair<Decl *, Decl *>>; |
66 | using ImportedCXXBaseSpecifierMap = |
67 | llvm::DenseMap<const CXXBaseSpecifier *, CXXBaseSpecifier *>; |
68 | |
69 | enum class ODRHandlingType { Conservative, Liberal }; |
70 | |
71 | // An ImportPath is the list of the AST nodes which we visit during an |
72 | // Import call. |
73 | // If node `A` depends on node `B` then the path contains an `A`->`B` edge. |
74 | // From the call stack of the import functions we can read the very same |
75 | // path. |
76 | // |
77 | // Now imagine the following AST, where the `->` represents dependency in |
78 | // therms of the import. |
79 | // ``` |
80 | // A->B->C->D |
81 | // `->E |
82 | // ``` |
83 | // We would like to import A. |
84 | // The import behaves like a DFS, so we will visit the nodes in this order: |
85 | // ABCDE. |
86 | // During the visitation we will have the following ImportPaths: |
87 | // ``` |
88 | // A |
89 | // AB |
90 | // ABC |
91 | // ABCD |
92 | // ABC |
93 | // AB |
94 | // ABE |
95 | // AB |
96 | // A |
97 | // ``` |
98 | // If during the visit of E there is an error then we set an error for E, |
99 | // then as the call stack shrinks for B, then for A: |
100 | // ``` |
101 | // A |
102 | // AB |
103 | // ABC |
104 | // ABCD |
105 | // ABC |
106 | // AB |
107 | // ABE // Error! Set an error to E |
108 | // AB // Set an error to B |
109 | // A // Set an error to A |
110 | // ``` |
111 | // However, during the import we could import C and D without any error and |
112 | // they are independent from A,B and E. |
113 | // We must not set up an error for C and D. |
114 | // So, at the end of the import we have an entry in `ImportDeclErrors` for |
115 | // A,B,E but not for C,D. |
116 | // |
117 | // Now what happens if there is a cycle in the import path? |
118 | // Let's consider this AST: |
119 | // ``` |
120 | // A->B->C->A |
121 | // `->E |
122 | // ``` |
123 | // During the visitation we will have the below ImportPaths and if during |
124 | // the visit of E there is an error then we will set up an error for E,B,A. |
125 | // But what's up with C? |
126 | // ``` |
127 | // A |
128 | // AB |
129 | // ABC |
130 | // ABCA |
131 | // ABC |
132 | // AB |
133 | // ABE // Error! Set an error to E |
134 | // AB // Set an error to B |
135 | // A // Set an error to A |
136 | // ``` |
137 | // This time we know that both B and C are dependent on A. |
138 | // This means we must set up an error for C too. |
139 | // As the call stack reverses back we get to A and we must set up an error |
140 | // to all nodes which depend on A (this includes C). |
141 | // But C is no longer on the import path, it just had been previously. |
142 | // Such situation can happen only if during the visitation we had a cycle. |
143 | // If we didn't have any cycle, then the normal way of passing an Error |
144 | // object through the call stack could handle the situation. |
145 | // This is why we must track cycles during the import process for each |
146 | // visited declaration. |
147 | class ImportPathTy { |
148 | public: |
149 | using VecTy = llvm::SmallVector<Decl *, 32>; |
150 | |
151 | void push(Decl *D) { |
152 | Nodes.push_back(Elt: D); |
153 | ++Aux[D]; |
154 | } |
155 | |
156 | void pop() { |
157 | if (Nodes.empty()) |
158 | return; |
159 | --Aux[Nodes.back()]; |
160 | Nodes.pop_back(); |
161 | } |
162 | |
163 | /// Returns true if the last element can be found earlier in the path. |
164 | bool hasCycleAtBack() const { |
165 | auto Pos = Aux.find(Val: Nodes.back()); |
166 | return Pos != Aux.end() && Pos->second > 1; |
167 | } |
168 | |
169 | using Cycle = llvm::iterator_range<VecTy::const_reverse_iterator>; |
170 | Cycle getCycleAtBack() const { |
171 | assert(Nodes.size() >= 2); |
172 | return Cycle(Nodes.rbegin(), |
173 | std::find(first: Nodes.rbegin() + 1, last: Nodes.rend(), val: Nodes.back()) + |
174 | 1); |
175 | } |
176 | |
177 | /// Returns the copy of the cycle. |
178 | VecTy copyCycleAtBack() const { |
179 | auto R = getCycleAtBack(); |
180 | return VecTy(R.begin(), R.end()); |
181 | } |
182 | |
183 | private: |
184 | // All nodes of the path. |
185 | VecTy Nodes; |
186 | // Auxiliary container to be able to answer "Do we have a cycle ending |
187 | // at last element?" as fast as possible. |
188 | // We count each Decl's occurrence over the path. |
189 | llvm::SmallDenseMap<Decl *, int, 32> Aux; |
190 | }; |
191 | |
192 | private: |
193 | std::shared_ptr<ASTImporterSharedState> SharedState = nullptr; |
194 | |
195 | /// The path which we go through during the import of a given AST node. |
196 | ImportPathTy ImportPath; |
197 | /// Sometimes we have to save some part of an import path, so later we can |
198 | /// set up properties to the saved nodes. |
199 | /// We may have several of these import paths associated to one Decl. |
200 | using SavedImportPathsForOneDecl = |
201 | llvm::SmallVector<ImportPathTy::VecTy, 32>; |
202 | using SavedImportPathsTy = |
203 | llvm::SmallDenseMap<Decl *, SavedImportPathsForOneDecl, 32>; |
204 | SavedImportPathsTy SavedImportPaths; |
205 | |
206 | /// The contexts we're importing to and from. |
207 | ASTContext &ToContext, &FromContext; |
208 | |
209 | /// The file managers we're importing to and from. |
210 | FileManager &ToFileManager, &FromFileManager; |
211 | |
212 | /// Whether to perform a minimal import. |
213 | bool Minimal; |
214 | |
215 | ODRHandlingType ODRHandling; |
216 | |
217 | /// Whether the last diagnostic came from the "from" context. |
218 | bool LastDiagFromFrom = false; |
219 | |
220 | /// Mapping from the already-imported types in the "from" context |
221 | /// to the corresponding types in the "to" context. |
222 | llvm::DenseMap<const Type *, const Type *> ImportedTypes; |
223 | |
224 | /// Mapping from the already-imported declarations in the "from" |
225 | /// context to the corresponding declarations in the "to" context. |
226 | llvm::DenseMap<Decl *, Decl *> ImportedDecls; |
227 | |
228 | /// Mapping from the already-imported declarations in the "from" |
229 | /// context to the error status of the import of that declaration. |
230 | /// This map contains only the declarations that were not correctly |
231 | /// imported. The same declaration may or may not be included in |
232 | /// ImportedDecls. This map is updated continuously during imports and never |
233 | /// cleared (like ImportedDecls). |
234 | llvm::DenseMap<Decl *, ASTImportError> ImportDeclErrors; |
235 | |
236 | /// Mapping from the already-imported declarations in the "to" |
237 | /// context to the corresponding declarations in the "from" context. |
238 | llvm::DenseMap<Decl *, Decl *> ImportedFromDecls; |
239 | |
240 | /// Mapping from the already-imported statements in the "from" |
241 | /// context to the corresponding statements in the "to" context. |
242 | llvm::DenseMap<Stmt *, Stmt *> ImportedStmts; |
243 | |
244 | /// Mapping from the already-imported FileIDs in the "from" source |
245 | /// manager to the corresponding FileIDs in the "to" source manager. |
246 | llvm::DenseMap<FileID, FileID> ImportedFileIDs; |
247 | |
248 | /// Mapping from the already-imported CXXBasesSpecifier in |
249 | /// the "from" source manager to the corresponding CXXBasesSpecifier |
250 | /// in the "to" source manager. |
251 | ImportedCXXBaseSpecifierMap ImportedCXXBaseSpecifiers; |
252 | |
253 | /// Declaration (from, to) pairs that are known not to be equivalent |
254 | /// (which we have already complained about). |
255 | NonEquivalentDeclSet NonEquivalentDecls; |
256 | |
257 | using FoundDeclsTy = SmallVector<NamedDecl *, 2>; |
258 | FoundDeclsTy findDeclsInToCtx(DeclContext *DC, DeclarationName Name); |
259 | |
260 | void AddToLookupTable(Decl *ToD); |
261 | llvm::Error ImportAttrs(Decl *ToD, Decl *FromD); |
262 | |
263 | protected: |
264 | /// Can be overwritten by subclasses to implement their own import logic. |
265 | /// The overwritten method should call this method if it didn't import the |
266 | /// decl on its own. |
267 | virtual Expected<Decl *> ImportImpl(Decl *From); |
268 | |
269 | /// Used only in unittests to verify the behaviour of the error handling. |
270 | virtual bool returnWithErrorInTest() { return false; }; |
271 | |
272 | public: |
273 | |
274 | /// \param ToContext The context we'll be importing into. |
275 | /// |
276 | /// \param ToFileManager The file manager we'll be importing into. |
277 | /// |
278 | /// \param FromContext The context we'll be importing from. |
279 | /// |
280 | /// \param FromFileManager The file manager we'll be importing into. |
281 | /// |
282 | /// \param MinimalImport If true, the importer will attempt to import |
283 | /// as little as it can, e.g., by importing declarations as forward |
284 | /// declarations that can be completed at a later point. |
285 | /// |
286 | /// \param SharedState The importer specific lookup table which may be |
287 | /// shared amongst several ASTImporter objects. |
288 | /// If not set then the original C/C++ lookup is used. |
289 | ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, |
290 | ASTContext &FromContext, FileManager &FromFileManager, |
291 | bool MinimalImport, |
292 | std::shared_ptr<ASTImporterSharedState> SharedState = nullptr); |
293 | |
294 | virtual ~ASTImporter(); |
295 | |
296 | /// Whether the importer will perform a minimal import, creating |
297 | /// to-be-completed forward declarations when possible. |
298 | bool isMinimalImport() const { return Minimal; } |
299 | |
300 | void setODRHandling(ODRHandlingType T) { ODRHandling = T; } |
301 | |
302 | /// \brief Import the given object, returns the result. |
303 | /// |
304 | /// \param To Import the object into this variable. |
305 | /// \param From Object to import. |
306 | /// \return Error information (success or error). |
307 | template <typename ImportT> |
308 | [[nodiscard]] llvm::Error importInto(ImportT &To, const ImportT &From) { |
309 | auto ToOrErr = Import(From); |
310 | if (ToOrErr) |
311 | To = *ToOrErr; |
312 | return ToOrErr.takeError(); |
313 | } |
314 | |
315 | /// Import cleanup objects owned by ExprWithCleanup. |
316 | llvm::Expected<ExprWithCleanups::CleanupObject> |
317 | Import(ExprWithCleanups::CleanupObject From); |
318 | |
319 | /// Import the given type from the "from" context into the "to" |
320 | /// context. |
321 | /// |
322 | /// \returns The equivalent type in the "to" context, or the import error. |
323 | llvm::Expected<const Type *> Import(const Type *FromT); |
324 | |
325 | /// Import the given qualified type from the "from" context into the "to" |
326 | /// context. A null type is imported as a null type (no error). |
327 | /// |
328 | /// \returns The equivalent type in the "to" context, or the import error. |
329 | llvm::Expected<QualType> Import(QualType FromT); |
330 | |
331 | /// Import the given type source information from the |
332 | /// "from" context into the "to" context. |
333 | /// |
334 | /// \returns The equivalent type source information in the "to" |
335 | /// context, or the import error. |
336 | llvm::Expected<TypeSourceInfo *> Import(TypeSourceInfo *FromTSI); |
337 | |
338 | /// Import the given attribute from the "from" context into the |
339 | /// "to" context. |
340 | /// |
341 | /// \returns The equivalent attribute in the "to" context, or the import |
342 | /// error. |
343 | llvm::Expected<Attr *> Import(const Attr *FromAttr); |
344 | |
345 | /// Import the given declaration from the "from" context into the |
346 | /// "to" context. |
347 | /// |
348 | /// \returns The equivalent declaration in the "to" context, or the import |
349 | /// error. |
350 | llvm::Expected<Decl *> Import(Decl *FromD); |
351 | llvm::Expected<const Decl *> Import(const Decl *FromD) { |
352 | return Import(FromD: const_cast<Decl *>(FromD)); |
353 | } |
354 | |
355 | llvm::Expected<InheritedConstructor> |
356 | Import(const InheritedConstructor &From); |
357 | |
358 | /// Return the copy of the given declaration in the "to" context if |
359 | /// it has already been imported from the "from" context. Otherwise return |
360 | /// nullptr. |
361 | Decl *GetAlreadyImportedOrNull(const Decl *FromD) const; |
362 | |
363 | /// Return the translation unit from where the declaration was |
364 | /// imported. If it does not exist nullptr is returned. |
365 | TranslationUnitDecl *GetFromTU(Decl *ToD); |
366 | |
367 | /// Return the declaration in the "from" context from which the declaration |
368 | /// in the "to" context was imported. If it was not imported or of the wrong |
369 | /// type a null value is returned. |
370 | template <typename DeclT> |
371 | std::optional<DeclT *> getImportedFromDecl(const DeclT *ToD) const { |
372 | auto FromI = ImportedFromDecls.find(ToD); |
373 | if (FromI == ImportedFromDecls.end()) |
374 | return {}; |
375 | auto *FromD = dyn_cast<DeclT>(FromI->second); |
376 | if (!FromD) |
377 | return {}; |
378 | return FromD; |
379 | } |
380 | |
381 | /// Import the given declaration context from the "from" |
382 | /// AST context into the "to" AST context. |
383 | /// |
384 | /// \returns the equivalent declaration context in the "to" |
385 | /// context, or error value. |
386 | llvm::Expected<DeclContext *> ImportContext(DeclContext *FromDC); |
387 | |
388 | /// Import the given expression from the "from" context into the |
389 | /// "to" context. |
390 | /// |
391 | /// \returns The equivalent expression in the "to" context, or the import |
392 | /// error. |
393 | llvm::Expected<Expr *> Import(Expr *FromE); |
394 | |
395 | /// Import the given statement from the "from" context into the |
396 | /// "to" context. |
397 | /// |
398 | /// \returns The equivalent statement in the "to" context, or the import |
399 | /// error. |
400 | llvm::Expected<Stmt *> Import(Stmt *FromS); |
401 | |
402 | /// Import the given nested-name-specifier from the "from" |
403 | /// context into the "to" context. |
404 | /// |
405 | /// \returns The equivalent nested-name-specifier in the "to" |
406 | /// context, or the import error. |
407 | llvm::Expected<NestedNameSpecifier *> Import(NestedNameSpecifier *FromNNS); |
408 | |
409 | /// Import the given nested-name-specifier-loc from the "from" |
410 | /// context into the "to" context. |
411 | /// |
412 | /// \returns The equivalent nested-name-specifier-loc in the "to" |
413 | /// context, or the import error. |
414 | llvm::Expected<NestedNameSpecifierLoc> |
415 | Import(NestedNameSpecifierLoc FromNNS); |
416 | |
417 | /// Import the given template name from the "from" context into the |
418 | /// "to" context, or the import error. |
419 | llvm::Expected<TemplateName> Import(TemplateName From); |
420 | |
421 | /// Import the given source location from the "from" context into |
422 | /// the "to" context. |
423 | /// |
424 | /// \returns The equivalent source location in the "to" context, or the |
425 | /// import error. |
426 | llvm::Expected<SourceLocation> Import(SourceLocation FromLoc); |
427 | |
428 | /// Import the given source range from the "from" context into |
429 | /// the "to" context. |
430 | /// |
431 | /// \returns The equivalent source range in the "to" context, or the import |
432 | /// error. |
433 | llvm::Expected<SourceRange> Import(SourceRange FromRange); |
434 | |
435 | /// Import the given declaration name from the "from" |
436 | /// context into the "to" context. |
437 | /// |
438 | /// \returns The equivalent declaration name in the "to" context, or the |
439 | /// import error. |
440 | llvm::Expected<DeclarationName> Import(DeclarationName FromName); |
441 | |
442 | /// Import the given identifier from the "from" context |
443 | /// into the "to" context. |
444 | /// |
445 | /// \returns The equivalent identifier in the "to" context. Note: It |
446 | /// returns nullptr only if the FromId was nullptr. |
447 | IdentifierInfo *Import(const IdentifierInfo *FromId); |
448 | |
449 | /// Import the given Objective-C selector from the "from" |
450 | /// context into the "to" context. |
451 | /// |
452 | /// \returns The equivalent selector in the "to" context, or the import |
453 | /// error. |
454 | llvm::Expected<Selector> Import(Selector FromSel); |
455 | |
456 | /// Import the given file ID from the "from" context into the |
457 | /// "to" context. |
458 | /// |
459 | /// \returns The equivalent file ID in the source manager of the "to" |
460 | /// context, or the import error. |
461 | llvm::Expected<FileID> Import(FileID, bool IsBuiltin = false); |
462 | |
463 | /// Import the given C++ constructor initializer from the "from" |
464 | /// context into the "to" context. |
465 | /// |
466 | /// \returns The equivalent initializer in the "to" context, or the import |
467 | /// error. |
468 | llvm::Expected<CXXCtorInitializer *> Import(CXXCtorInitializer *FromInit); |
469 | |
470 | /// Import the given CXXBaseSpecifier from the "from" context into |
471 | /// the "to" context. |
472 | /// |
473 | /// \returns The equivalent CXXBaseSpecifier in the source manager of the |
474 | /// "to" context, or the import error. |
475 | llvm::Expected<CXXBaseSpecifier *> Import(const CXXBaseSpecifier *FromSpec); |
476 | |
477 | /// Import the given APValue from the "from" context into |
478 | /// the "to" context. |
479 | /// |
480 | /// \return the equivalent APValue in the "to" context or the import |
481 | /// error. |
482 | llvm::Expected<APValue> Import(const APValue &FromValue); |
483 | |
484 | /// Import the definition of the given declaration, including all of |
485 | /// the declarations it contains. |
486 | [[nodiscard]] llvm::Error ImportDefinition(Decl *From); |
487 | |
488 | /// Cope with a name conflict when importing a declaration into the |
489 | /// given context. |
490 | /// |
491 | /// This routine is invoked whenever there is a name conflict while |
492 | /// importing a declaration. The returned name will become the name of the |
493 | /// imported declaration. By default, the returned name is the same as the |
494 | /// original name, leaving the conflict unresolve such that name lookup |
495 | /// for this name is likely to find an ambiguity later. |
496 | /// |
497 | /// Subclasses may override this routine to resolve the conflict, e.g., by |
498 | /// renaming the declaration being imported. |
499 | /// |
500 | /// \param Name the name of the declaration being imported, which conflicts |
501 | /// with other declarations. |
502 | /// |
503 | /// \param DC the declaration context (in the "to" AST context) in which |
504 | /// the name is being imported. |
505 | /// |
506 | /// \param IDNS the identifier namespace in which the name will be found. |
507 | /// |
508 | /// \param Decls the set of declarations with the same name as the |
509 | /// declaration being imported. |
510 | /// |
511 | /// \param NumDecls the number of conflicting declarations in \p Decls. |
512 | /// |
513 | /// \returns the name that the newly-imported declaration should have. Or |
514 | /// an error if we can't handle the name conflict. |
515 | virtual Expected<DeclarationName> |
516 | HandleNameConflict(DeclarationName Name, DeclContext *DC, unsigned IDNS, |
517 | NamedDecl **Decls, unsigned NumDecls); |
518 | |
519 | /// Retrieve the context that AST nodes are being imported into. |
520 | ASTContext &getToContext() const { return ToContext; } |
521 | |
522 | /// Retrieve the context that AST nodes are being imported from. |
523 | ASTContext &getFromContext() const { return FromContext; } |
524 | |
525 | /// Retrieve the file manager that AST nodes are being imported into. |
526 | FileManager &getToFileManager() const { return ToFileManager; } |
527 | |
528 | /// Retrieve the file manager that AST nodes are being imported from. |
529 | FileManager &getFromFileManager() const { return FromFileManager; } |
530 | |
531 | /// Report a diagnostic in the "to" context. |
532 | DiagnosticBuilder ToDiag(SourceLocation Loc, unsigned DiagID); |
533 | |
534 | /// Report a diagnostic in the "from" context. |
535 | DiagnosticBuilder FromDiag(SourceLocation Loc, unsigned DiagID); |
536 | |
537 | /// Return the set of declarations that we know are not equivalent. |
538 | NonEquivalentDeclSet &getNonEquivalentDecls() { return NonEquivalentDecls; } |
539 | |
540 | /// Called for ObjCInterfaceDecl, ObjCProtocolDecl, and TagDecl. |
541 | /// Mark the Decl as complete, filling it in as much as possible. |
542 | /// |
543 | /// \param D A declaration in the "to" context. |
544 | virtual void CompleteDecl(Decl* D); |
545 | |
546 | /// Subclasses can override this function to observe all of the \c From -> |
547 | /// \c To declaration mappings as they are imported. |
548 | virtual void Imported(Decl *From, Decl *To) {} |
549 | |
550 | void RegisterImportedDecl(Decl *FromD, Decl *ToD); |
551 | |
552 | /// Store and assign the imported declaration to its counterpart. |
553 | /// It may happen that several decls from the 'from' context are mapped to |
554 | /// the same decl in the 'to' context. |
555 | Decl *MapImported(Decl *From, Decl *To); |
556 | |
557 | /// Called by StructuralEquivalenceContext. If a RecordDecl is |
558 | /// being compared to another RecordDecl as part of import, completing the |
559 | /// other RecordDecl may trigger importation of the first RecordDecl. This |
560 | /// happens especially for anonymous structs. If the original of the second |
561 | /// RecordDecl can be found, we can complete it without the need for |
562 | /// importation, eliminating this loop. |
563 | virtual Decl *GetOriginalDecl(Decl *To) { return nullptr; } |
564 | |
565 | /// Return if import of the given declaration has failed and if yes |
566 | /// the kind of the problem. This gives the first error encountered with |
567 | /// the node. |
568 | std::optional<ASTImportError> getImportDeclErrorIfAny(Decl *FromD) const; |
569 | |
570 | /// Mark (newly) imported declaration with error. |
571 | void setImportDeclError(Decl *From, ASTImportError Error); |
572 | |
573 | /// Determine whether the given types are structurally |
574 | /// equivalent. |
575 | bool IsStructurallyEquivalent(QualType From, QualType To, |
576 | bool Complain = true); |
577 | |
578 | /// Determine the index of a field in its parent record. |
579 | /// F should be a field (or indirect field) declaration. |
580 | /// \returns The index of the field in its parent context (starting from 0). |
581 | /// On error `std::nullopt` is returned (parent context is non-record). |
582 | static std::optional<unsigned> getFieldIndex(Decl *F); |
583 | }; |
584 | |
585 | } // namespace clang |
586 | |
587 | #endif // LLVM_CLANG_AST_ASTIMPORTER_H |
588 | |