| //===- ASTImporter.cpp - Importing ASTs from other Contexts ---------------===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the ASTImporter class which imports AST nodes from one |
| // context into another context. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/ASTImporter.h" |
| #include "clang/AST/ASTImporterSharedState.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/ASTDiagnostic.h" |
| #include "clang/AST/ASTStructuralEquivalence.h" |
| #include "clang/AST/Attr.h" |
| #include "clang/AST/Decl.h" |
| #include "clang/AST/DeclAccessPair.h" |
| #include "clang/AST/DeclBase.h" |
| #include "clang/AST/DeclCXX.h" |
| #include "clang/AST/DeclFriend.h" |
| #include "clang/AST/DeclGroup.h" |
| #include "clang/AST/DeclObjC.h" |
| #include "clang/AST/DeclTemplate.h" |
| #include "clang/AST/DeclVisitor.h" |
| #include "clang/AST/DeclarationName.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/ExprCXX.h" |
| #include "clang/AST/ExprObjC.h" |
| #include "clang/AST/ExternalASTSource.h" |
| #include "clang/AST/LambdaCapture.h" |
| #include "clang/AST/NestedNameSpecifier.h" |
| #include "clang/AST/OperationKinds.h" |
| #include "clang/AST/Stmt.h" |
| #include "clang/AST/StmtCXX.h" |
| #include "clang/AST/StmtObjC.h" |
| #include "clang/AST/StmtVisitor.h" |
| #include "clang/AST/TemplateBase.h" |
| #include "clang/AST/TemplateName.h" |
| #include "clang/AST/Type.h" |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/AST/TypeVisitor.h" |
| #include "clang/AST/UnresolvedSet.h" |
| #include "clang/Basic/ExceptionSpecificationType.h" |
| #include "clang/Basic/FileManager.h" |
| #include "clang/Basic/IdentifierTable.h" |
| #include "clang/Basic/LLVM.h" |
| #include "clang/Basic/LangOptions.h" |
| #include "clang/Basic/SourceLocation.h" |
| #include "clang/Basic/SourceManager.h" |
| #include "clang/Basic/Specifiers.h" |
| #include "llvm/ADT/APSInt.h" |
| #include "llvm/ADT/ArrayRef.h" |
| #include "llvm/ADT/DenseMap.h" |
| #include "llvm/ADT/None.h" |
| #include "llvm/ADT/Optional.h" |
| #include "llvm/ADT/ScopeExit.h" |
| #include "llvm/ADT/STLExtras.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/Support/Casting.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include <algorithm> |
| #include <cassert> |
| #include <cstddef> |
| #include <memory> |
| #include <type_traits> |
| #include <utility> |
| |
| namespace clang { |
| |
| using llvm::make_error; |
| using llvm::Error; |
| using llvm::Expected; |
| using ExpectedType = llvm::Expected<QualType>; |
| using ExpectedStmt = llvm::Expected<Stmt *>; |
| using ExpectedExpr = llvm::Expected<Expr *>; |
| using ExpectedDecl = llvm::Expected<Decl *>; |
| using ExpectedSLoc = llvm::Expected<SourceLocation>; |
| using ExpectedName = llvm::Expected<DeclarationName>; |
| |
| std::string ImportError::toString() const { |
| // FIXME: Improve error texts. |
| switch (Error) { |
| case NameConflict: |
| return "NameConflict"; |
| case UnsupportedConstruct: |
| return "UnsupportedConstruct"; |
| case Unknown: |
| return "Unknown error"; |
| } |
| llvm_unreachable("Invalid error code."); |
| return "Invalid error code."; |
| } |
| |
| void ImportError::log(raw_ostream &OS) const { |
| OS << toString(); |
| } |
| |
| std::error_code ImportError::convertToErrorCode() const { |
| llvm_unreachable("Function not implemented."); |
| } |
| |
| char ImportError::ID; |
| |
| template <class T> |
| SmallVector<Decl *, 2> |
| getCanonicalForwardRedeclChain(Redeclarable<T>* D) { |
| SmallVector<Decl *, 2> Redecls; |
| for (auto *R : D->getFirstDecl()->redecls()) { |
| if (R != D->getFirstDecl()) |
| Redecls.push_back(R); |
| } |
| Redecls.push_back(D->getFirstDecl()); |
| std::reverse(Redecls.begin(), Redecls.end()); |
| return Redecls; |
| } |
| |
| SmallVector<Decl*, 2> getCanonicalForwardRedeclChain(Decl* D) { |
| if (auto *FD = dyn_cast<FunctionDecl>(D)) |
| return getCanonicalForwardRedeclChain<FunctionDecl>(FD); |
| if (auto *VD = dyn_cast<VarDecl>(D)) |
| return getCanonicalForwardRedeclChain<VarDecl>(VD); |
| if (auto *TD = dyn_cast<TagDecl>(D)) |
| return getCanonicalForwardRedeclChain<TagDecl>(TD); |
| llvm_unreachable("Bad declaration kind"); |
| } |
| |
| void updateFlags(const Decl *From, Decl *To) { |
| // Check if some flags or attrs are new in 'From' and copy into 'To'. |
| // FIXME: Other flags or attrs? |
| if (From->isUsed(false) && !To->isUsed(false)) |
| To->setIsUsed(); |
| } |
| |
| class ASTNodeImporter : public TypeVisitor<ASTNodeImporter, ExpectedType>, |
| public DeclVisitor<ASTNodeImporter, ExpectedDecl>, |
| public StmtVisitor<ASTNodeImporter, ExpectedStmt> { |
| ASTImporter &Importer; |
| |
| // Use this instead of Importer.importInto . |
| template <typename ImportT> |
| LLVM_NODISCARD Error importInto(ImportT &To, const ImportT &From) { |
| return Importer.importInto(To, From); |
| } |
| |
| // Use this to import pointers of specific type. |
| template <typename ImportT> |
| LLVM_NODISCARD Error importInto(ImportT *&To, ImportT *From) { |
| auto ToOrErr = Importer.Import(From); |
| if (ToOrErr) |
| To = cast_or_null<ImportT>(*ToOrErr); |
| return ToOrErr.takeError(); |
| } |
| |
| // Call the import function of ASTImporter for a baseclass of type `T` and |
| // cast the return value to `T`. |
| template <typename T> |
| Expected<T *> import(T *From) { |
| auto ToOrErr = Importer.Import(From); |
| if (!ToOrErr) |
| return ToOrErr.takeError(); |
| return cast_or_null<T>(*ToOrErr); |
| } |
| |
| template <typename T> |
| Expected<T *> import(const T *From) { |
| return import(const_cast<T *>(From)); |
| } |
| |
| // Call the import function of ASTImporter for type `T`. |
| template <typename T> |
| Expected<T> import(const T &From) { |
| return Importer.Import(From); |
| } |
| |
| // Import an Optional<T> by importing the contained T, if any. |
| template<typename T> |
| Expected<Optional<T>> import(Optional<T> From) { |
| if (!From) |
| return Optional<T>(); |
| return import(*From); |
| } |
| |
| template <class T> |
| Expected<std::tuple<T>> |
| importSeq(const T &From) { |
| Expected<T> ToOrErr = import(From); |
| if (!ToOrErr) |
| return ToOrErr.takeError(); |
| return std::make_tuple<T>(std::move(*ToOrErr)); |
| } |
| |
| // Import multiple objects with a single function call. |
| // This should work for every type for which a variant of `import` exists. |
| // The arguments are processed from left to right and import is stopped on |
| // first error. |
| template <class THead, class... TTail> |
| Expected<std::tuple<THead, TTail...>> |
| importSeq(const THead &FromHead, const TTail &...FromTail) { |
| Expected<std::tuple<THead>> ToHeadOrErr = importSeq(FromHead); |
| if (!ToHeadOrErr) |
| return ToHeadOrErr.takeError(); |
| Expected<std::tuple<TTail...>> ToTailOrErr = importSeq(FromTail...); |
| if (!ToTailOrErr) |
| return ToTailOrErr.takeError(); |
| return std::tuple_cat(*ToHeadOrErr, *ToTailOrErr); |
| } |
| |
| // Wrapper for an overload set. |
| template <typename ToDeclT> struct CallOverloadedCreateFun { |
| template <typename... Args> |
| auto operator()(Args &&... args) |
| -> decltype(ToDeclT::Create(std::forward<Args>(args)...)) { |
| return ToDeclT::Create(std::forward<Args>(args)...); |
| } |
| }; |
| |
| // Always use these functions to create a Decl during import. There are |
| // certain tasks which must be done after the Decl was created, e.g. we |
| // must immediately register that as an imported Decl. The parameter `ToD` |
| // will be set to the newly created Decl or if had been imported before |
| // then to the already imported Decl. Returns a bool value set to true if |
| // the `FromD` had been imported before. |
| template <typename ToDeclT, typename FromDeclT, typename... Args> |
| LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, |
| Args &&... args) { |
| // There may be several overloads of ToDeclT::Create. We must make sure |
| // to call the one which would be chosen by the arguments, thus we use a |
| // wrapper for the overload set. |
| CallOverloadedCreateFun<ToDeclT> OC; |
| return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, |
| std::forward<Args>(args)...); |
| } |
| // Use this overload if a special Type is needed to be created. E.g if we |
| // want to create a `TypeAliasDecl` and assign that to a `TypedefNameDecl` |
| // then: |
| // TypedefNameDecl *ToTypedef; |
| // GetImportedOrCreateDecl<TypeAliasDecl>(ToTypedef, FromD, ...); |
| template <typename NewDeclT, typename ToDeclT, typename FromDeclT, |
| typename... Args> |
| LLVM_NODISCARD bool GetImportedOrCreateDecl(ToDeclT *&ToD, FromDeclT *FromD, |
| Args &&... args) { |
| CallOverloadedCreateFun<NewDeclT> OC; |
| return GetImportedOrCreateSpecialDecl(ToD, OC, FromD, |
| std::forward<Args>(args)...); |
| } |
| // Use this version if a special create function must be |
| // used, e.g. CXXRecordDecl::CreateLambda . |
| template <typename ToDeclT, typename CreateFunT, typename FromDeclT, |
| typename... Args> |
| LLVM_NODISCARD bool |
| GetImportedOrCreateSpecialDecl(ToDeclT *&ToD, CreateFunT CreateFun, |
| FromDeclT *FromD, Args &&... args) { |
| if (Importer.getImportDeclErrorIfAny(FromD)) { |
| ToD = nullptr; |
| return true; // Already imported but with error. |
| } |
| ToD = cast_or_null<ToDeclT>(Importer.GetAlreadyImportedOrNull(FromD)); |
| if (ToD) |
| return true; // Already imported. |
| ToD = CreateFun(std::forward<Args>(args)...); |
| // Keep track of imported Decls. |
| Importer.RegisterImportedDecl(FromD, ToD); |
| InitializeImportedDecl(FromD, ToD); |
| return false; // A new Decl is created. |
| } |
| |
| void InitializeImportedDecl(Decl *FromD, Decl *ToD) { |
| ToD->IdentifierNamespace = FromD->IdentifierNamespace; |
| if (FromD->hasAttrs()) |
| for (const Attr *FromAttr : FromD->getAttrs()) { |
| // FIXME: Return of the error here is not possible until store of |
| // import errors is implemented. |
| auto ToAttrOrErr = import(FromAttr); |
| if (ToAttrOrErr) |
| ToD->addAttr(*ToAttrOrErr); |
| else |
| llvm::consumeError(ToAttrOrErr.takeError()); |
| } |
| if (FromD->isUsed()) |
| ToD->setIsUsed(); |
| if (FromD->isImplicit()) |
| ToD->setImplicit(); |
| } |
| |
| // Check if we have found an existing definition. Returns with that |
| // definition if yes, otherwise returns null. |
| Decl *FindAndMapDefinition(FunctionDecl *D, FunctionDecl *FoundFunction) { |
| const FunctionDecl *Definition = nullptr; |
| if (D->doesThisDeclarationHaveABody() && |
| FoundFunction->hasBody(Definition)) |
| return Importer.MapImported(D, const_cast<FunctionDecl *>(Definition)); |
| return nullptr; |
| } |
| |
| public: |
| explicit ASTNodeImporter(ASTImporter &Importer) : Importer(Importer) {} |
| |
| using TypeVisitor<ASTNodeImporter, ExpectedType>::Visit; |
| using DeclVisitor<ASTNodeImporter, ExpectedDecl>::Visit; |
| using StmtVisitor<ASTNodeImporter, ExpectedStmt>::Visit; |
| |
| // Importing types |
| ExpectedType VisitType(const Type *T); |
| ExpectedType VisitAtomicType(const AtomicType *T); |
| ExpectedType VisitBuiltinType(const BuiltinType *T); |
| ExpectedType VisitDecayedType(const DecayedType *T); |
| ExpectedType VisitComplexType(const ComplexType *T); |
| ExpectedType VisitPointerType(const PointerType *T); |
| ExpectedType VisitBlockPointerType(const BlockPointerType *T); |
| ExpectedType VisitLValueReferenceType(const LValueReferenceType *T); |
| ExpectedType VisitRValueReferenceType(const RValueReferenceType *T); |
| ExpectedType VisitMemberPointerType(const MemberPointerType *T); |
| ExpectedType VisitConstantArrayType(const ConstantArrayType *T); |
| ExpectedType VisitIncompleteArrayType(const IncompleteArrayType *T); |
| ExpectedType VisitVariableArrayType(const VariableArrayType *T); |
| ExpectedType VisitDependentSizedArrayType(const DependentSizedArrayType *T); |
| // FIXME: DependentSizedExtVectorType |
| ExpectedType VisitVectorType(const VectorType *T); |
| ExpectedType VisitExtVectorType(const ExtVectorType *T); |
| ExpectedType VisitFunctionNoProtoType(const FunctionNoProtoType *T); |
| ExpectedType VisitFunctionProtoType(const FunctionProtoType *T); |
| ExpectedType VisitUnresolvedUsingType(const UnresolvedUsingType *T); |
| ExpectedType VisitParenType(const ParenType *T); |
| ExpectedType VisitTypedefType(const TypedefType *T); |
| ExpectedType VisitTypeOfExprType(const TypeOfExprType *T); |
| // FIXME: DependentTypeOfExprType |
| ExpectedType VisitTypeOfType(const TypeOfType *T); |
| ExpectedType VisitDecltypeType(const DecltypeType *T); |
| ExpectedType VisitUnaryTransformType(const UnaryTransformType *T); |
| ExpectedType VisitAutoType(const AutoType *T); |
| ExpectedType VisitInjectedClassNameType(const InjectedClassNameType *T); |
| // FIXME: DependentDecltypeType |
| ExpectedType VisitRecordType(const RecordType *T); |
| ExpectedType VisitEnumType(const EnumType *T); |
| ExpectedType VisitAttributedType(const AttributedType *T); |
| ExpectedType VisitTemplateTypeParmType(const TemplateTypeParmType *T); |
| ExpectedType VisitSubstTemplateTypeParmType( |
| const SubstTemplateTypeParmType *T); |
| ExpectedType VisitTemplateSpecializationType( |
| const TemplateSpecializationType *T); |
| ExpectedType VisitElaboratedType(const ElaboratedType *T); |
| ExpectedType VisitDependentNameType(const DependentNameType *T); |
| ExpectedType VisitPackExpansionType(const PackExpansionType *T); |
| ExpectedType VisitDependentTemplateSpecializationType( |
| const DependentTemplateSpecializationType *T); |
| ExpectedType VisitObjCInterfaceType(const ObjCInterfaceType *T); |
| ExpectedType VisitObjCObjectType(const ObjCObjectType *T); |
| ExpectedType VisitObjCObjectPointerType(const ObjCObjectPointerType *T); |
| |
| // Importing declarations |
| Error ImportDeclParts( |
| NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, |
| DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc); |
| Error ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD = nullptr); |
| Error ImportDeclarationNameLoc( |
| const DeclarationNameInfo &From, DeclarationNameInfo &To); |
| Error ImportDeclContext(DeclContext *FromDC, bool ForceImport = false); |
| Error ImportDeclContext( |
| Decl *From, DeclContext *&ToDC, DeclContext *&ToLexicalDC); |
| Error ImportImplicitMethods(const CXXRecordDecl *From, CXXRecordDecl *To); |
| |
| Expected<CXXCastPath> ImportCastPath(CastExpr *E); |
| |
| using Designator = DesignatedInitExpr::Designator; |
| |
| /// What we should import from the definition. |
| enum ImportDefinitionKind { |
| /// Import the default subset of the definition, which might be |
| /// nothing (if minimal import is set) or might be everything (if minimal |
| /// import is not set). |
| IDK_Default, |
| /// Import everything. |
| IDK_Everything, |
| /// Import only the bare bones needed to establish a valid |
| /// DeclContext. |
| IDK_Basic |
| }; |
| |
| bool shouldForceImportDeclContext(ImportDefinitionKind IDK) { |
| return IDK == IDK_Everything || |
| (IDK == IDK_Default && !Importer.isMinimalImport()); |
| } |
| |
| Error ImportInitializer(VarDecl *From, VarDecl *To); |
| Error ImportDefinition( |
| RecordDecl *From, RecordDecl *To, |
| ImportDefinitionKind Kind = IDK_Default); |
| Error ImportDefinition( |
| EnumDecl *From, EnumDecl *To, |
| ImportDefinitionKind Kind = IDK_Default); |
| Error ImportDefinition( |
| ObjCInterfaceDecl *From, ObjCInterfaceDecl *To, |
| ImportDefinitionKind Kind = IDK_Default); |
| Error ImportDefinition( |
| ObjCProtocolDecl *From, ObjCProtocolDecl *To, |
| ImportDefinitionKind Kind = IDK_Default); |
| Error ImportTemplateArguments( |
| const TemplateArgument *FromArgs, unsigned NumFromArgs, |
| SmallVectorImpl<TemplateArgument> &ToArgs); |
| Expected<TemplateArgument> |
| ImportTemplateArgument(const TemplateArgument &From); |
| |
| template <typename InContainerTy> |
| Error ImportTemplateArgumentListInfo( |
| const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo); |
| |
| template<typename InContainerTy> |
| Error ImportTemplateArgumentListInfo( |
| SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, |
| const InContainerTy &Container, TemplateArgumentListInfo &Result); |
| |
| using TemplateArgsTy = SmallVector<TemplateArgument, 8>; |
| using FunctionTemplateAndArgsTy = |
| std::tuple<FunctionTemplateDecl *, TemplateArgsTy>; |
| Expected<FunctionTemplateAndArgsTy> |
| ImportFunctionTemplateWithTemplateArgsFromSpecialization( |
| FunctionDecl *FromFD); |
| Error ImportTemplateParameterLists(const DeclaratorDecl *FromD, |
| DeclaratorDecl *ToD); |
| |
| Error ImportTemplateInformation(FunctionDecl *FromFD, FunctionDecl *ToFD); |
| |
| Error ImportFunctionDeclBody(FunctionDecl *FromFD, FunctionDecl *ToFD); |
| |
| Error ImportDefaultArgOfParmVarDecl(const ParmVarDecl *FromParam, |
| ParmVarDecl *ToParam); |
| |
| template <typename T> |
| bool hasSameVisibilityContext(T *Found, T *From); |
| |
| bool IsStructuralMatch(Decl *From, Decl *To, bool Complain); |
| bool IsStructuralMatch(RecordDecl *FromRecord, RecordDecl *ToRecord, |
| bool Complain = true); |
| bool IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, |
| bool Complain = true); |
| bool IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToRecord); |
| bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); |
| bool IsStructuralMatch(FunctionTemplateDecl *From, |
| FunctionTemplateDecl *To); |
| bool IsStructuralMatch(FunctionDecl *From, FunctionDecl *To); |
| bool IsStructuralMatch(ClassTemplateDecl *From, ClassTemplateDecl *To); |
| bool IsStructuralMatch(VarTemplateDecl *From, VarTemplateDecl *To); |
| ExpectedDecl VisitDecl(Decl *D); |
| ExpectedDecl VisitImportDecl(ImportDecl *D); |
| ExpectedDecl VisitEmptyDecl(EmptyDecl *D); |
| ExpectedDecl VisitAccessSpecDecl(AccessSpecDecl *D); |
| ExpectedDecl VisitStaticAssertDecl(StaticAssertDecl *D); |
| ExpectedDecl VisitTranslationUnitDecl(TranslationUnitDecl *D); |
| ExpectedDecl VisitNamespaceDecl(NamespaceDecl *D); |
| ExpectedDecl VisitNamespaceAliasDecl(NamespaceAliasDecl *D); |
| ExpectedDecl VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias); |
| ExpectedDecl VisitTypedefDecl(TypedefDecl *D); |
| ExpectedDecl VisitTypeAliasDecl(TypeAliasDecl *D); |
| ExpectedDecl VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D); |
| ExpectedDecl VisitLabelDecl(LabelDecl *D); |
| ExpectedDecl VisitEnumDecl(EnumDecl *D); |
| ExpectedDecl VisitRecordDecl(RecordDecl *D); |
| ExpectedDecl VisitEnumConstantDecl(EnumConstantDecl *D); |
| ExpectedDecl VisitFunctionDecl(FunctionDecl *D); |
| ExpectedDecl VisitCXXMethodDecl(CXXMethodDecl *D); |
| ExpectedDecl VisitCXXConstructorDecl(CXXConstructorDecl *D); |
| ExpectedDecl VisitCXXDestructorDecl(CXXDestructorDecl *D); |
| ExpectedDecl VisitCXXConversionDecl(CXXConversionDecl *D); |
| ExpectedDecl VisitFieldDecl(FieldDecl *D); |
| ExpectedDecl VisitIndirectFieldDecl(IndirectFieldDecl *D); |
| ExpectedDecl VisitFriendDecl(FriendDecl *D); |
| ExpectedDecl VisitObjCIvarDecl(ObjCIvarDecl *D); |
| ExpectedDecl VisitVarDecl(VarDecl *D); |
| ExpectedDecl VisitImplicitParamDecl(ImplicitParamDecl *D); |
| ExpectedDecl VisitParmVarDecl(ParmVarDecl *D); |
| ExpectedDecl VisitObjCMethodDecl(ObjCMethodDecl *D); |
| ExpectedDecl VisitObjCTypeParamDecl(ObjCTypeParamDecl *D); |
| ExpectedDecl VisitObjCCategoryDecl(ObjCCategoryDecl *D); |
| ExpectedDecl VisitObjCProtocolDecl(ObjCProtocolDecl *D); |
| ExpectedDecl VisitLinkageSpecDecl(LinkageSpecDecl *D); |
| ExpectedDecl VisitUsingDecl(UsingDecl *D); |
| ExpectedDecl VisitUsingShadowDecl(UsingShadowDecl *D); |
| ExpectedDecl VisitUsingDirectiveDecl(UsingDirectiveDecl *D); |
| ExpectedDecl VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D); |
| ExpectedDecl VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D); |
| |
| Expected<ObjCTypeParamList *> |
| ImportObjCTypeParamList(ObjCTypeParamList *list); |
| |
| ExpectedDecl VisitObjCInterfaceDecl(ObjCInterfaceDecl *D); |
| ExpectedDecl VisitObjCCategoryImplDecl(ObjCCategoryImplDecl *D); |
| ExpectedDecl VisitObjCImplementationDecl(ObjCImplementationDecl *D); |
| ExpectedDecl VisitObjCPropertyDecl(ObjCPropertyDecl *D); |
| ExpectedDecl VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); |
| ExpectedDecl VisitTemplateTypeParmDecl(TemplateTypeParmDecl *D); |
| ExpectedDecl VisitNonTypeTemplateParmDecl(NonTypeTemplateParmDecl *D); |
| ExpectedDecl VisitTemplateTemplateParmDecl(TemplateTemplateParmDecl *D); |
| ExpectedDecl VisitClassTemplateDecl(ClassTemplateDecl *D); |
| ExpectedDecl VisitClassTemplateSpecializationDecl( |
| ClassTemplateSpecializationDecl *D); |
| ExpectedDecl VisitVarTemplateDecl(VarTemplateDecl *D); |
| ExpectedDecl VisitVarTemplateSpecializationDecl(VarTemplateSpecializationDecl *D); |
| ExpectedDecl VisitFunctionTemplateDecl(FunctionTemplateDecl *D); |
| |
| // Importing statements |
| ExpectedStmt VisitStmt(Stmt *S); |
| ExpectedStmt VisitGCCAsmStmt(GCCAsmStmt *S); |
| ExpectedStmt VisitDeclStmt(DeclStmt *S); |
| ExpectedStmt VisitNullStmt(NullStmt *S); |
| ExpectedStmt VisitCompoundStmt(CompoundStmt *S); |
| ExpectedStmt VisitCaseStmt(CaseStmt *S); |
| ExpectedStmt VisitDefaultStmt(DefaultStmt *S); |
| ExpectedStmt VisitLabelStmt(LabelStmt *S); |
| ExpectedStmt VisitAttributedStmt(AttributedStmt *S); |
| ExpectedStmt VisitIfStmt(IfStmt *S); |
| ExpectedStmt VisitSwitchStmt(SwitchStmt *S); |
| ExpectedStmt VisitWhileStmt(WhileStmt *S); |
| ExpectedStmt VisitDoStmt(DoStmt *S); |
| ExpectedStmt VisitForStmt(ForStmt *S); |
| ExpectedStmt VisitGotoStmt(GotoStmt *S); |
| ExpectedStmt VisitIndirectGotoStmt(IndirectGotoStmt *S); |
| ExpectedStmt VisitContinueStmt(ContinueStmt *S); |
| ExpectedStmt VisitBreakStmt(BreakStmt *S); |
| ExpectedStmt VisitReturnStmt(ReturnStmt *S); |
| // FIXME: MSAsmStmt |
| // FIXME: SEHExceptStmt |
| // FIXME: SEHFinallyStmt |
| // FIXME: SEHTryStmt |
| // FIXME: SEHLeaveStmt |
| // FIXME: CapturedStmt |
| ExpectedStmt VisitCXXCatchStmt(CXXCatchStmt *S); |
| ExpectedStmt VisitCXXTryStmt(CXXTryStmt *S); |
| ExpectedStmt VisitCXXForRangeStmt(CXXForRangeStmt *S); |
| // FIXME: MSDependentExistsStmt |
| ExpectedStmt VisitObjCForCollectionStmt(ObjCForCollectionStmt *S); |
| ExpectedStmt VisitObjCAtCatchStmt(ObjCAtCatchStmt *S); |
| ExpectedStmt VisitObjCAtFinallyStmt(ObjCAtFinallyStmt *S); |
| ExpectedStmt VisitObjCAtTryStmt(ObjCAtTryStmt *S); |
| ExpectedStmt VisitObjCAtSynchronizedStmt(ObjCAtSynchronizedStmt *S); |
| ExpectedStmt VisitObjCAtThrowStmt(ObjCAtThrowStmt *S); |
| ExpectedStmt VisitObjCAutoreleasePoolStmt(ObjCAutoreleasePoolStmt *S); |
| |
| // Importing expressions |
| ExpectedStmt VisitExpr(Expr *E); |
| ExpectedStmt VisitVAArgExpr(VAArgExpr *E); |
| ExpectedStmt VisitChooseExpr(ChooseExpr *E); |
| ExpectedStmt VisitGNUNullExpr(GNUNullExpr *E); |
| ExpectedStmt VisitPredefinedExpr(PredefinedExpr *E); |
| ExpectedStmt VisitDeclRefExpr(DeclRefExpr *E); |
| ExpectedStmt VisitImplicitValueInitExpr(ImplicitValueInitExpr *E); |
| ExpectedStmt VisitDesignatedInitExpr(DesignatedInitExpr *E); |
| ExpectedStmt VisitCXXNullPtrLiteralExpr(CXXNullPtrLiteralExpr *E); |
| ExpectedStmt VisitIntegerLiteral(IntegerLiteral *E); |
| ExpectedStmt VisitFloatingLiteral(FloatingLiteral *E); |
| ExpectedStmt VisitImaginaryLiteral(ImaginaryLiteral *E); |
| ExpectedStmt VisitCharacterLiteral(CharacterLiteral *E); |
| ExpectedStmt VisitStringLiteral(StringLiteral *E); |
| ExpectedStmt VisitCompoundLiteralExpr(CompoundLiteralExpr *E); |
| ExpectedStmt VisitAtomicExpr(AtomicExpr *E); |
| ExpectedStmt VisitAddrLabelExpr(AddrLabelExpr *E); |
| ExpectedStmt VisitConstantExpr(ConstantExpr *E); |
| ExpectedStmt VisitParenExpr(ParenExpr *E); |
| ExpectedStmt VisitParenListExpr(ParenListExpr *E); |
| ExpectedStmt VisitStmtExpr(StmtExpr *E); |
| ExpectedStmt VisitUnaryOperator(UnaryOperator *E); |
| ExpectedStmt VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *E); |
| ExpectedStmt VisitBinaryOperator(BinaryOperator *E); |
| ExpectedStmt VisitConditionalOperator(ConditionalOperator *E); |
| ExpectedStmt VisitBinaryConditionalOperator(BinaryConditionalOperator *E); |
| ExpectedStmt VisitOpaqueValueExpr(OpaqueValueExpr *E); |
| ExpectedStmt VisitArrayTypeTraitExpr(ArrayTypeTraitExpr *E); |
| ExpectedStmt VisitExpressionTraitExpr(ExpressionTraitExpr *E); |
| ExpectedStmt VisitArraySubscriptExpr(ArraySubscriptExpr *E); |
| ExpectedStmt VisitCompoundAssignOperator(CompoundAssignOperator *E); |
| ExpectedStmt VisitImplicitCastExpr(ImplicitCastExpr *E); |
| ExpectedStmt VisitExplicitCastExpr(ExplicitCastExpr *E); |
| ExpectedStmt VisitOffsetOfExpr(OffsetOfExpr *OE); |
| ExpectedStmt VisitCXXThrowExpr(CXXThrowExpr *E); |
| ExpectedStmt VisitCXXNoexceptExpr(CXXNoexceptExpr *E); |
| ExpectedStmt VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E); |
| ExpectedStmt VisitCXXScalarValueInitExpr(CXXScalarValueInitExpr *E); |
| ExpectedStmt VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E); |
| ExpectedStmt VisitCXXTemporaryObjectExpr(CXXTemporaryObjectExpr *E); |
| ExpectedStmt VisitMaterializeTemporaryExpr(MaterializeTemporaryExpr *E); |
| ExpectedStmt VisitPackExpansionExpr(PackExpansionExpr *E); |
| ExpectedStmt VisitSizeOfPackExpr(SizeOfPackExpr *E); |
| ExpectedStmt VisitCXXNewExpr(CXXNewExpr *E); |
| ExpectedStmt VisitCXXDeleteExpr(CXXDeleteExpr *E); |
| ExpectedStmt VisitCXXConstructExpr(CXXConstructExpr *E); |
| ExpectedStmt VisitCXXMemberCallExpr(CXXMemberCallExpr *E); |
| ExpectedStmt VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E); |
| ExpectedStmt VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E); |
| ExpectedStmt VisitCXXUnresolvedConstructExpr(CXXUnresolvedConstructExpr *E); |
| ExpectedStmt VisitUnresolvedLookupExpr(UnresolvedLookupExpr *E); |
| ExpectedStmt VisitUnresolvedMemberExpr(UnresolvedMemberExpr *E); |
| ExpectedStmt VisitExprWithCleanups(ExprWithCleanups *E); |
| ExpectedStmt VisitCXXThisExpr(CXXThisExpr *E); |
| ExpectedStmt VisitCXXBoolLiteralExpr(CXXBoolLiteralExpr *E); |
| ExpectedStmt VisitCXXPseudoDestructorExpr(CXXPseudoDestructorExpr *E); |
| ExpectedStmt VisitMemberExpr(MemberExpr *E); |
| ExpectedStmt VisitCallExpr(CallExpr *E); |
| ExpectedStmt VisitLambdaExpr(LambdaExpr *LE); |
| ExpectedStmt VisitInitListExpr(InitListExpr *E); |
| ExpectedStmt VisitCXXStdInitializerListExpr(CXXStdInitializerListExpr *E); |
| ExpectedStmt VisitCXXInheritedCtorInitExpr(CXXInheritedCtorInitExpr *E); |
| ExpectedStmt VisitArrayInitLoopExpr(ArrayInitLoopExpr *E); |
| ExpectedStmt VisitArrayInitIndexExpr(ArrayInitIndexExpr *E); |
| ExpectedStmt VisitCXXDefaultInitExpr(CXXDefaultInitExpr *E); |
| ExpectedStmt VisitCXXNamedCastExpr(CXXNamedCastExpr *E); |
| ExpectedStmt VisitSubstNonTypeTemplateParmExpr(SubstNonTypeTemplateParmExpr *E); |
| ExpectedStmt VisitTypeTraitExpr(TypeTraitExpr *E); |
| ExpectedStmt VisitCXXTypeidExpr(CXXTypeidExpr *E); |
| |
| template<typename IIter, typename OIter> |
| Error ImportArrayChecked(IIter Ibegin, IIter Iend, OIter Obegin) { |
| using ItemT = typename std::remove_reference<decltype(*Obegin)>::type; |
| for (; Ibegin != Iend; ++Ibegin, ++Obegin) { |
| Expected<ItemT> ToOrErr = import(*Ibegin); |
| if (!ToOrErr) |
| return ToOrErr.takeError(); |
| *Obegin = *ToOrErr; |
| } |
| return Error::success(); |
| } |
| |
| // Import every item from a container structure into an output container. |
| // If error occurs, stops at first error and returns the error. |
| // The output container should have space for all needed elements (it is not |
| // expanded, new items are put into from the beginning). |
| template<typename InContainerTy, typename OutContainerTy> |
| Error ImportContainerChecked( |
| const InContainerTy &InContainer, OutContainerTy &OutContainer) { |
| return ImportArrayChecked( |
| InContainer.begin(), InContainer.end(), OutContainer.begin()); |
| } |
| |
| template<typename InContainerTy, typename OIter> |
| Error ImportArrayChecked(const InContainerTy &InContainer, OIter Obegin) { |
| return ImportArrayChecked(InContainer.begin(), InContainer.end(), Obegin); |
| } |
| |
| Error ImportOverriddenMethods(CXXMethodDecl *ToMethod, |
| CXXMethodDecl *FromMethod); |
| |
| Expected<FunctionDecl *> FindFunctionTemplateSpecialization( |
| FunctionDecl *FromFD); |
| }; |
| |
| template <typename InContainerTy> |
| Error ASTNodeImporter::ImportTemplateArgumentListInfo( |
| SourceLocation FromLAngleLoc, SourceLocation FromRAngleLoc, |
| const InContainerTy &Container, TemplateArgumentListInfo &Result) { |
| auto ToLAngleLocOrErr = import(FromLAngleLoc); |
| if (!ToLAngleLocOrErr) |
| return ToLAngleLocOrErr.takeError(); |
| auto ToRAngleLocOrErr = import(FromRAngleLoc); |
| if (!ToRAngleLocOrErr) |
| return ToRAngleLocOrErr.takeError(); |
| |
| TemplateArgumentListInfo ToTAInfo(*ToLAngleLocOrErr, *ToRAngleLocOrErr); |
| if (auto Err = ImportTemplateArgumentListInfo(Container, ToTAInfo)) |
| return Err; |
| Result = ToTAInfo; |
| return Error::success(); |
| } |
| |
| template <> |
| Error ASTNodeImporter::ImportTemplateArgumentListInfo<TemplateArgumentListInfo>( |
| const TemplateArgumentListInfo &From, TemplateArgumentListInfo &Result) { |
| return ImportTemplateArgumentListInfo( |
| From.getLAngleLoc(), From.getRAngleLoc(), From.arguments(), Result); |
| } |
| |
| template <> |
| Error ASTNodeImporter::ImportTemplateArgumentListInfo< |
| ASTTemplateArgumentListInfo>( |
| const ASTTemplateArgumentListInfo &From, |
| TemplateArgumentListInfo &Result) { |
| return ImportTemplateArgumentListInfo( |
| From.LAngleLoc, From.RAngleLoc, From.arguments(), Result); |
| } |
| |
| Expected<ASTNodeImporter::FunctionTemplateAndArgsTy> |
| ASTNodeImporter::ImportFunctionTemplateWithTemplateArgsFromSpecialization( |
| FunctionDecl *FromFD) { |
| assert(FromFD->getTemplatedKind() == |
| FunctionDecl::TK_FunctionTemplateSpecialization); |
| |
| FunctionTemplateAndArgsTy Result; |
| |
| auto *FTSInfo = FromFD->getTemplateSpecializationInfo(); |
| if (Error Err = importInto(std::get<0>(Result), FTSInfo->getTemplate())) |
| return std::move(Err); |
| |
| // Import template arguments. |
| auto TemplArgs = FTSInfo->TemplateArguments->asArray(); |
| if (Error Err = ImportTemplateArguments(TemplArgs.data(), TemplArgs.size(), |
| std::get<1>(Result))) |
| return std::move(Err); |
| |
| return Result; |
| } |
| |
| template <> |
| Expected<TemplateParameterList *> |
| ASTNodeImporter::import(TemplateParameterList *From) { |
| SmallVector<NamedDecl *, 4> To(From->size()); |
| if (Error Err = ImportContainerChecked(*From, To)) |
| return std::move(Err); |
| |
| ExpectedExpr ToRequiresClause = import(From->getRequiresClause()); |
| if (!ToRequiresClause) |
| return ToRequiresClause.takeError(); |
| |
| auto ToTemplateLocOrErr = import(From->getTemplateLoc()); |
| if (!ToTemplateLocOrErr) |
| return ToTemplateLocOrErr.takeError(); |
| auto ToLAngleLocOrErr = import(From->getLAngleLoc()); |
| if (!ToLAngleLocOrErr) |
| return ToLAngleLocOrErr.takeError(); |
| auto ToRAngleLocOrErr = import(From->getRAngleLoc()); |
| if (!ToRAngleLocOrErr) |
| return ToRAngleLocOrErr.takeError(); |
| |
| return TemplateParameterList::Create( |
| Importer.getToContext(), |
| *ToTemplateLocOrErr, |
| *ToLAngleLocOrErr, |
| To, |
| *ToRAngleLocOrErr, |
| *ToRequiresClause); |
| } |
| |
| template <> |
| Expected<TemplateArgument> |
| ASTNodeImporter::import(const TemplateArgument &From) { |
| switch (From.getKind()) { |
| case TemplateArgument::Null: |
| return TemplateArgument(); |
| |
| case TemplateArgument::Type: { |
| ExpectedType ToTypeOrErr = import(From.getAsType()); |
| if (!ToTypeOrErr) |
| return ToTypeOrErr.takeError(); |
| return TemplateArgument(*ToTypeOrErr); |
| } |
| |
| case TemplateArgument::Integral: { |
| ExpectedType ToTypeOrErr = import(From.getIntegralType()); |
| if (!ToTypeOrErr) |
| return ToTypeOrErr.takeError(); |
| return TemplateArgument(From, *ToTypeOrErr); |
| } |
| |
| case TemplateArgument::Declaration: { |
| Expected<ValueDecl *> ToOrErr = import(From.getAsDecl()); |
| if (!ToOrErr) |
| return ToOrErr.takeError(); |
| ExpectedType ToTypeOrErr = import(From.getParamTypeForDecl()); |
| if (!ToTypeOrErr) |
| return ToTypeOrErr.takeError(); |
| return TemplateArgument(*ToOrErr, *ToTypeOrErr); |
| } |
| |
| case TemplateArgument::NullPtr: { |
| ExpectedType ToTypeOrErr = import(From.getNullPtrType()); |
| if (!ToTypeOrErr) |
| return ToTypeOrErr.takeError(); |
| return TemplateArgument(*ToTypeOrErr, /*isNullPtr*/true); |
| } |
| |
| case TemplateArgument::Template: { |
| Expected<TemplateName> ToTemplateOrErr = import(From.getAsTemplate()); |
| if (!ToTemplateOrErr) |
| return ToTemplateOrErr.takeError(); |
| |
| return TemplateArgument(*ToTemplateOrErr); |
| } |
| |
| case TemplateArgument::TemplateExpansion: { |
| Expected<TemplateName> ToTemplateOrErr = |
| import(From.getAsTemplateOrTemplatePattern()); |
| if (!ToTemplateOrErr) |
| return ToTemplateOrErr.takeError(); |
| |
| return TemplateArgument( |
| *ToTemplateOrErr, From.getNumTemplateExpansions()); |
| } |
| |
| case TemplateArgument::Expression: |
| if (ExpectedExpr ToExpr = import(From.getAsExpr())) |
| return TemplateArgument(*ToExpr); |
| else |
| return ToExpr.takeError(); |
| |
| case TemplateArgument::Pack: { |
| SmallVector<TemplateArgument, 2> ToPack; |
| ToPack.reserve(From.pack_size()); |
| if (Error Err = ImportTemplateArguments( |
| From.pack_begin(), From.pack_size(), ToPack)) |
| return std::move(Err); |
| |
| return TemplateArgument( |
| llvm::makeArrayRef(ToPack).copy(Importer.getToContext())); |
| } |
| } |
| |
| llvm_unreachable("Invalid template argument kind"); |
| } |
| |
| template <> |
| Expected<TemplateArgumentLoc> |
| ASTNodeImporter::import(const TemplateArgumentLoc &TALoc) { |
| Expected<TemplateArgument> ArgOrErr = import(TALoc.getArgument()); |
| if (!ArgOrErr) |
| return ArgOrErr.takeError(); |
| TemplateArgument Arg = *ArgOrErr; |
| |
| TemplateArgumentLocInfo FromInfo = TALoc.getLocInfo(); |
| |
| TemplateArgumentLocInfo ToInfo; |
| if (Arg.getKind() == TemplateArgument::Expression) { |
| ExpectedExpr E = import(FromInfo.getAsExpr()); |
| if (!E) |
| return E.takeError(); |
| ToInfo = TemplateArgumentLocInfo(*E); |
| } else if (Arg.getKind() == TemplateArgument::Type) { |
| if (auto TSIOrErr = import(FromInfo.getAsTypeSourceInfo())) |
| ToInfo = TemplateArgumentLocInfo(*TSIOrErr); |
| else |
| return TSIOrErr.takeError(); |
| } else { |
| auto ToTemplateQualifierLocOrErr = |
| import(FromInfo.getTemplateQualifierLoc()); |
| if (!ToTemplateQualifierLocOrErr) |
| return ToTemplateQualifierLocOrErr.takeError(); |
| auto ToTemplateNameLocOrErr = import(FromInfo.getTemplateNameLoc()); |
| if (!ToTemplateNameLocOrErr) |
| return ToTemplateNameLocOrErr.takeError(); |
| auto ToTemplateEllipsisLocOrErr = |
| import(FromInfo.getTemplateEllipsisLoc()); |
| if (!ToTemplateEllipsisLocOrErr) |
| return ToTemplateEllipsisLocOrErr.takeError(); |
| |
| ToInfo = TemplateArgumentLocInfo( |
| *ToTemplateQualifierLocOrErr, |
| *ToTemplateNameLocOrErr, |
| *ToTemplateEllipsisLocOrErr); |
| } |
| |
| return TemplateArgumentLoc(Arg, ToInfo); |
| } |
| |
| template <> |
| Expected<DeclGroupRef> ASTNodeImporter::import(const DeclGroupRef &DG) { |
| if (DG.isNull()) |
| return DeclGroupRef::Create(Importer.getToContext(), nullptr, 0); |
| size_t NumDecls = DG.end() - DG.begin(); |
| SmallVector<Decl *, 1> ToDecls; |
| ToDecls.reserve(NumDecls); |
| for (Decl *FromD : DG) { |
| if (auto ToDOrErr = import(FromD)) |
| ToDecls.push_back(*ToDOrErr); |
| else |
| return ToDOrErr.takeError(); |
| } |
| return DeclGroupRef::Create(Importer.getToContext(), |
| ToDecls.begin(), |
| NumDecls); |
| } |
| |
| template <> |
| Expected<ASTNodeImporter::Designator> |
| ASTNodeImporter::import(const Designator &D) { |
| if (D.isFieldDesignator()) { |
| IdentifierInfo *ToFieldName = Importer.Import(D.getFieldName()); |
| |
| ExpectedSLoc ToDotLocOrErr = import(D.getDotLoc()); |
| if (!ToDotLocOrErr) |
| return ToDotLocOrErr.takeError(); |
| |
| ExpectedSLoc ToFieldLocOrErr = import(D.getFieldLoc()); |
| if (!ToFieldLocOrErr) |
| return ToFieldLocOrErr.takeError(); |
| |
| return Designator(ToFieldName, *ToDotLocOrErr, *ToFieldLocOrErr); |
| } |
| |
| ExpectedSLoc ToLBracketLocOrErr = import(D.getLBracketLoc()); |
| if (!ToLBracketLocOrErr) |
| return ToLBracketLocOrErr.takeError(); |
| |
| ExpectedSLoc ToRBracketLocOrErr = import(D.getRBracketLoc()); |
| if (!ToRBracketLocOrErr) |
| return ToRBracketLocOrErr.takeError(); |
| |
| if (D.isArrayDesignator()) |
| return Designator(D.getFirstExprIndex(), |
| *ToLBracketLocOrErr, *ToRBracketLocOrErr); |
| |
| ExpectedSLoc ToEllipsisLocOrErr = import(D.getEllipsisLoc()); |
| if (!ToEllipsisLocOrErr) |
| return ToEllipsisLocOrErr.takeError(); |
| |
| assert(D.isArrayRangeDesignator()); |
| return Designator( |
| D.getFirstExprIndex(), *ToLBracketLocOrErr, *ToEllipsisLocOrErr, |
| *ToRBracketLocOrErr); |
| } |
| |
| template <> |
| Expected<LambdaCapture> ASTNodeImporter::import(const LambdaCapture &From) { |
| VarDecl *Var = nullptr; |
| if (From.capturesVariable()) { |
| if (auto VarOrErr = import(From.getCapturedVar())) |
| Var = *VarOrErr; |
| else |
| return VarOrErr.takeError(); |
| } |
| |
| auto LocationOrErr = import(From.getLocation()); |
| if (!LocationOrErr) |
| return LocationOrErr.takeError(); |
| |
| SourceLocation EllipsisLoc; |
| if (From.isPackExpansion()) |
| if (Error Err = importInto(EllipsisLoc, From.getEllipsisLoc())) |
| return std::move(Err); |
| |
| return LambdaCapture( |
| *LocationOrErr, From.isImplicit(), From.getCaptureKind(), Var, |
| EllipsisLoc); |
| } |
| |
| template <typename T> |
| bool ASTNodeImporter::hasSameVisibilityContext(T *Found, T *From) { |
| if (From->hasExternalFormalLinkage()) |
| return Found->hasExternalFormalLinkage(); |
| if (Importer.GetFromTU(Found) != From->getTranslationUnitDecl()) |
| return false; |
| if (From->isInAnonymousNamespace()) |
| return Found->isInAnonymousNamespace(); |
| else |
| return !Found->isInAnonymousNamespace() && |
| !Found->hasExternalFormalLinkage(); |
| } |
| |
| template <> |
| bool ASTNodeImporter::hasSameVisibilityContext(TypedefNameDecl *Found, |
| TypedefNameDecl *From) { |
| if (From->isInAnonymousNamespace() && Found->isInAnonymousNamespace()) |
| return Importer.GetFromTU(Found) == From->getTranslationUnitDecl(); |
| return From->isInAnonymousNamespace() == Found->isInAnonymousNamespace(); |
| } |
| |
| } // namespace clang |
| |
| //---------------------------------------------------------------------------- |
| // Import Types |
| //---------------------------------------------------------------------------- |
| |
| using namespace clang; |
| |
| ExpectedType ASTNodeImporter::VisitType(const Type *T) { |
| Importer.FromDiag(SourceLocation(), diag::err_unsupported_ast_node) |
| << T->getTypeClassName(); |
| return make_error<ImportError>(ImportError::UnsupportedConstruct); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitAtomicType(const AtomicType *T){ |
| ExpectedType UnderlyingTypeOrErr = import(T->getValueType()); |
| if (!UnderlyingTypeOrErr) |
| return UnderlyingTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getAtomicType(*UnderlyingTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitBuiltinType(const BuiltinType *T) { |
| switch (T->getKind()) { |
| #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ |
| case BuiltinType::Id: \ |
| return Importer.getToContext().SingletonId; |
| #include "clang/Basic/OpenCLImageTypes.def" |
| #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ |
| case BuiltinType::Id: \ |
| return Importer.getToContext().Id##Ty; |
| #include "clang/Basic/OpenCLExtensionTypes.def" |
| #define SVE_TYPE(Name, Id, SingletonId) \ |
| case BuiltinType::Id: \ |
| return Importer.getToContext().SingletonId; |
| #include "clang/Basic/AArch64SVEACLETypes.def" |
| #define SHARED_SINGLETON_TYPE(Expansion) |
| #define BUILTIN_TYPE(Id, SingletonId) \ |
| case BuiltinType::Id: return Importer.getToContext().SingletonId; |
| #include "clang/AST/BuiltinTypes.def" |
| |
| // FIXME: for Char16, Char32, and NullPtr, make sure that the "to" |
| // context supports C++. |
| |
| // FIXME: for ObjCId, ObjCClass, and ObjCSel, make sure that the "to" |
| // context supports ObjC. |
| |
| case BuiltinType::Char_U: |
| // The context we're importing from has an unsigned 'char'. If we're |
| // importing into a context with a signed 'char', translate to |
| // 'unsigned char' instead. |
| if (Importer.getToContext().getLangOpts().CharIsSigned) |
| return Importer.getToContext().UnsignedCharTy; |
| |
| return Importer.getToContext().CharTy; |
| |
| case BuiltinType::Char_S: |
| // The context we're importing from has an unsigned 'char'. If we're |
| // importing into a context with a signed 'char', translate to |
| // 'unsigned char' instead. |
| if (!Importer.getToContext().getLangOpts().CharIsSigned) |
| return Importer.getToContext().SignedCharTy; |
| |
| return Importer.getToContext().CharTy; |
| |
| case BuiltinType::WChar_S: |
| case BuiltinType::WChar_U: |
| // FIXME: If not in C++, shall we translate to the C equivalent of |
| // wchar_t? |
| return Importer.getToContext().WCharTy; |
| } |
| |
| llvm_unreachable("Invalid BuiltinType Kind!"); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitDecayedType(const DecayedType *T) { |
| ExpectedType ToOriginalTypeOrErr = import(T->getOriginalType()); |
| if (!ToOriginalTypeOrErr) |
| return ToOriginalTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getDecayedType(*ToOriginalTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitComplexType(const ComplexType *T) { |
| ExpectedType ToElementTypeOrErr = import(T->getElementType()); |
| if (!ToElementTypeOrErr) |
| return ToElementTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getComplexType(*ToElementTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitPointerType(const PointerType *T) { |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getPointerType(*ToPointeeTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitBlockPointerType(const BlockPointerType *T) { |
| // FIXME: Check for blocks support in "to" context. |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getBlockPointerType(*ToPointeeTypeOrErr); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitLValueReferenceType(const LValueReferenceType *T) { |
| // FIXME: Check for C++ support in "to" context. |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeTypeAsWritten()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getLValueReferenceType(*ToPointeeTypeOrErr); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitRValueReferenceType(const RValueReferenceType *T) { |
| // FIXME: Check for C++0x support in "to" context. |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeTypeAsWritten()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getRValueReferenceType(*ToPointeeTypeOrErr); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitMemberPointerType(const MemberPointerType *T) { |
| // FIXME: Check for C++ support in "to" context. |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| ExpectedType ClassTypeOrErr = import(QualType(T->getClass(), 0)); |
| if (!ClassTypeOrErr) |
| return ClassTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getMemberPointerType( |
| *ToPointeeTypeOrErr, (*ClassTypeOrErr).getTypePtr()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitConstantArrayType(const ConstantArrayType *T) { |
| QualType ToElementType; |
| const Expr *ToSizeExpr; |
| if (auto Imp = importSeq(T->getElementType(), T->getSizeExpr())) |
| std::tie(ToElementType, ToSizeExpr) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| return Importer.getToContext().getConstantArrayType( |
| ToElementType, T->getSize(), ToSizeExpr, T->getSizeModifier(), |
| T->getIndexTypeCVRQualifiers()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitIncompleteArrayType(const IncompleteArrayType *T) { |
| ExpectedType ToElementTypeOrErr = import(T->getElementType()); |
| if (!ToElementTypeOrErr) |
| return ToElementTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getIncompleteArrayType(*ToElementTypeOrErr, |
| T->getSizeModifier(), |
| T->getIndexTypeCVRQualifiers()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitVariableArrayType(const VariableArrayType *T) { |
| QualType ToElementType; |
| Expr *ToSizeExpr; |
| SourceRange ToBracketsRange; |
| if (auto Imp = importSeq( |
| T->getElementType(), T->getSizeExpr(), T->getBracketsRange())) |
| std::tie(ToElementType, ToSizeExpr, ToBracketsRange) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| return Importer.getToContext().getVariableArrayType( |
| ToElementType, ToSizeExpr, T->getSizeModifier(), |
| T->getIndexTypeCVRQualifiers(), ToBracketsRange); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitDependentSizedArrayType( |
| const DependentSizedArrayType *T) { |
| QualType ToElementType; |
| Expr *ToSizeExpr; |
| SourceRange ToBracketsRange; |
| if (auto Imp = importSeq( |
| T->getElementType(), T->getSizeExpr(), T->getBracketsRange())) |
| std::tie(ToElementType, ToSizeExpr, ToBracketsRange) = *Imp; |
| else |
| return Imp.takeError(); |
| // SizeExpr may be null if size is not specified directly. |
| // For example, 'int a[]'. |
| |
| return Importer.getToContext().getDependentSizedArrayType( |
| ToElementType, ToSizeExpr, T->getSizeModifier(), |
| T->getIndexTypeCVRQualifiers(), ToBracketsRange); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitVectorType(const VectorType *T) { |
| ExpectedType ToElementTypeOrErr = import(T->getElementType()); |
| if (!ToElementTypeOrErr) |
| return ToElementTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getVectorType(*ToElementTypeOrErr, |
| T->getNumElements(), |
| T->getVectorKind()); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitExtVectorType(const ExtVectorType *T) { |
| ExpectedType ToElementTypeOrErr = import(T->getElementType()); |
| if (!ToElementTypeOrErr) |
| return ToElementTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getExtVectorType(*ToElementTypeOrErr, |
| T->getNumElements()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitFunctionNoProtoType(const FunctionNoProtoType *T) { |
| // FIXME: What happens if we're importing a function without a prototype |
| // into C++? Should we make it variadic? |
| ExpectedType ToReturnTypeOrErr = import(T->getReturnType()); |
| if (!ToReturnTypeOrErr) |
| return ToReturnTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getFunctionNoProtoType(*ToReturnTypeOrErr, |
| T->getExtInfo()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitFunctionProtoType(const FunctionProtoType *T) { |
| ExpectedType ToReturnTypeOrErr = import(T->getReturnType()); |
| if (!ToReturnTypeOrErr) |
| return ToReturnTypeOrErr.takeError(); |
| |
| // Import argument types |
| SmallVector<QualType, 4> ArgTypes; |
| for (const auto &A : T->param_types()) { |
| ExpectedType TyOrErr = import(A); |
| if (!TyOrErr) |
| return TyOrErr.takeError(); |
| ArgTypes.push_back(*TyOrErr); |
| } |
| |
| // Import exception types |
| SmallVector<QualType, 4> ExceptionTypes; |
| for (const auto &E : T->exceptions()) { |
| ExpectedType TyOrErr = import(E); |
| if (!TyOrErr) |
| return TyOrErr.takeError(); |
| ExceptionTypes.push_back(*TyOrErr); |
| } |
| |
| FunctionProtoType::ExtProtoInfo FromEPI = T->getExtProtoInfo(); |
| FunctionProtoType::ExtProtoInfo ToEPI; |
| |
| auto Imp = importSeq( |
| FromEPI.ExceptionSpec.NoexceptExpr, |
| FromEPI.ExceptionSpec.SourceDecl, |
| FromEPI.ExceptionSpec.SourceTemplate); |
| if (!Imp) |
| return Imp.takeError(); |
| |
| ToEPI.ExtInfo = FromEPI.ExtInfo; |
| ToEPI.Variadic = FromEPI.Variadic; |
| ToEPI.HasTrailingReturn = FromEPI.HasTrailingReturn; |
| ToEPI.TypeQuals = FromEPI.TypeQuals; |
| ToEPI.RefQualifier = FromEPI.RefQualifier; |
| ToEPI.ExceptionSpec.Type = FromEPI.ExceptionSpec.Type; |
| ToEPI.ExceptionSpec.Exceptions = ExceptionTypes; |
| std::tie( |
| ToEPI.ExceptionSpec.NoexceptExpr, |
| ToEPI.ExceptionSpec.SourceDecl, |
| ToEPI.ExceptionSpec.SourceTemplate) = *Imp; |
| |
| return Importer.getToContext().getFunctionType( |
| *ToReturnTypeOrErr, ArgTypes, ToEPI); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitUnresolvedUsingType( |
| const UnresolvedUsingType *T) { |
| UnresolvedUsingTypenameDecl *ToD; |
| Decl *ToPrevD; |
| if (auto Imp = importSeq(T->getDecl(), T->getDecl()->getPreviousDecl())) |
| std::tie(ToD, ToPrevD) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| return Importer.getToContext().getTypeDeclType( |
| ToD, cast_or_null<TypeDecl>(ToPrevD)); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitParenType(const ParenType *T) { |
| ExpectedType ToInnerTypeOrErr = import(T->getInnerType()); |
| if (!ToInnerTypeOrErr) |
| return ToInnerTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getParenType(*ToInnerTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitTypedefType(const TypedefType *T) { |
| Expected<TypedefNameDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getTypeDeclType(*ToDeclOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitTypeOfExprType(const TypeOfExprType *T) { |
| ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr()); |
| if (!ToExprOrErr) |
| return ToExprOrErr.takeError(); |
| |
| return Importer.getToContext().getTypeOfExprType(*ToExprOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitTypeOfType(const TypeOfType *T) { |
| ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); |
| if (!ToUnderlyingTypeOrErr) |
| return ToUnderlyingTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getTypeOfType(*ToUnderlyingTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitDecltypeType(const DecltypeType *T) { |
| // FIXME: Make sure that the "to" context supports C++0x! |
| ExpectedExpr ToExprOrErr = import(T->getUnderlyingExpr()); |
| if (!ToExprOrErr) |
| return ToExprOrErr.takeError(); |
| |
| ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); |
| if (!ToUnderlyingTypeOrErr) |
| return ToUnderlyingTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getDecltypeType( |
| *ToExprOrErr, *ToUnderlyingTypeOrErr); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitUnaryTransformType(const UnaryTransformType *T) { |
| ExpectedType ToBaseTypeOrErr = import(T->getBaseType()); |
| if (!ToBaseTypeOrErr) |
| return ToBaseTypeOrErr.takeError(); |
| |
| ExpectedType ToUnderlyingTypeOrErr = import(T->getUnderlyingType()); |
| if (!ToUnderlyingTypeOrErr) |
| return ToUnderlyingTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getUnaryTransformType( |
| *ToBaseTypeOrErr, *ToUnderlyingTypeOrErr, T->getUTTKind()); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitAutoType(const AutoType *T) { |
| // FIXME: Make sure that the "to" context supports C++11! |
| ExpectedType ToDeducedTypeOrErr = import(T->getDeducedType()); |
| if (!ToDeducedTypeOrErr) |
| return ToDeducedTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getAutoType(*ToDeducedTypeOrErr, |
| T->getKeyword(), |
| /*IsDependent*/false); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitInjectedClassNameType( |
| const InjectedClassNameType *T) { |
| Expected<CXXRecordDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| ExpectedType ToInjTypeOrErr = import(T->getInjectedSpecializationType()); |
| if (!ToInjTypeOrErr) |
| return ToInjTypeOrErr.takeError(); |
| |
| // FIXME: ASTContext::getInjectedClassNameType is not suitable for AST reading |
| // See comments in InjectedClassNameType definition for details |
| // return Importer.getToContext().getInjectedClassNameType(D, InjType); |
| enum { |
| TypeAlignmentInBits = 4, |
| TypeAlignment = 1 << TypeAlignmentInBits |
| }; |
| |
| return QualType(new (Importer.getToContext(), TypeAlignment) |
| InjectedClassNameType(*ToDeclOrErr, *ToInjTypeOrErr), 0); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitRecordType(const RecordType *T) { |
| Expected<RecordDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getTagDeclType(*ToDeclOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitEnumType(const EnumType *T) { |
| Expected<EnumDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getTagDeclType(*ToDeclOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitAttributedType(const AttributedType *T) { |
| ExpectedType ToModifiedTypeOrErr = import(T->getModifiedType()); |
| if (!ToModifiedTypeOrErr) |
| return ToModifiedTypeOrErr.takeError(); |
| ExpectedType ToEquivalentTypeOrErr = import(T->getEquivalentType()); |
| if (!ToEquivalentTypeOrErr) |
| return ToEquivalentTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getAttributedType(T->getAttrKind(), |
| *ToModifiedTypeOrErr, *ToEquivalentTypeOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitTemplateTypeParmType( |
| const TemplateTypeParmType *T) { |
| Expected<TemplateTypeParmDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getTemplateTypeParmType( |
| T->getDepth(), T->getIndex(), T->isParameterPack(), *ToDeclOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitSubstTemplateTypeParmType( |
| const SubstTemplateTypeParmType *T) { |
| ExpectedType ReplacedOrErr = import(QualType(T->getReplacedParameter(), 0)); |
| if (!ReplacedOrErr) |
| return ReplacedOrErr.takeError(); |
| const TemplateTypeParmType *Replaced = |
| cast<TemplateTypeParmType>((*ReplacedOrErr).getTypePtr()); |
| |
| ExpectedType ToReplacementTypeOrErr = import(T->getReplacementType()); |
| if (!ToReplacementTypeOrErr) |
| return ToReplacementTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getSubstTemplateTypeParmType( |
| Replaced, (*ToReplacementTypeOrErr).getCanonicalType()); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitTemplateSpecializationType( |
| const TemplateSpecializationType *T) { |
| auto ToTemplateOrErr = import(T->getTemplateName()); |
| if (!ToTemplateOrErr) |
| return ToTemplateOrErr.takeError(); |
| |
| SmallVector<TemplateArgument, 2> ToTemplateArgs; |
| if (Error Err = ImportTemplateArguments( |
| T->getArgs(), T->getNumArgs(), ToTemplateArgs)) |
| return std::move(Err); |
| |
| QualType ToCanonType; |
| if (!QualType(T, 0).isCanonical()) { |
| QualType FromCanonType |
| = Importer.getFromContext().getCanonicalType(QualType(T, 0)); |
| if (ExpectedType TyOrErr = import(FromCanonType)) |
| ToCanonType = *TyOrErr; |
| else |
| return TyOrErr.takeError(); |
| } |
| return Importer.getToContext().getTemplateSpecializationType(*ToTemplateOrErr, |
| ToTemplateArgs, |
| ToCanonType); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitElaboratedType(const ElaboratedType *T) { |
| // Note: the qualifier in an ElaboratedType is optional. |
| auto ToQualifierOrErr = import(T->getQualifier()); |
| if (!ToQualifierOrErr) |
| return ToQualifierOrErr.takeError(); |
| |
| ExpectedType ToNamedTypeOrErr = import(T->getNamedType()); |
| if (!ToNamedTypeOrErr) |
| return ToNamedTypeOrErr.takeError(); |
| |
| Expected<TagDecl *> ToOwnedTagDeclOrErr = import(T->getOwnedTagDecl()); |
| if (!ToOwnedTagDeclOrErr) |
| return ToOwnedTagDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getElaboratedType(T->getKeyword(), |
| *ToQualifierOrErr, |
| *ToNamedTypeOrErr, |
| *ToOwnedTagDeclOrErr); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitPackExpansionType(const PackExpansionType *T) { |
| ExpectedType ToPatternOrErr = import(T->getPattern()); |
| if (!ToPatternOrErr) |
| return ToPatternOrErr.takeError(); |
| |
| return Importer.getToContext().getPackExpansionType(*ToPatternOrErr, |
| T->getNumExpansions()); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitDependentTemplateSpecializationType( |
| const DependentTemplateSpecializationType *T) { |
| auto ToQualifierOrErr = import(T->getQualifier()); |
| if (!ToQualifierOrErr) |
| return ToQualifierOrErr.takeError(); |
| |
| IdentifierInfo *ToName = Importer.Import(T->getIdentifier()); |
| |
| SmallVector<TemplateArgument, 2> ToPack; |
| ToPack.reserve(T->getNumArgs()); |
| if (Error Err = ImportTemplateArguments( |
| T->getArgs(), T->getNumArgs(), ToPack)) |
| return std::move(Err); |
| |
| return Importer.getToContext().getDependentTemplateSpecializationType( |
| T->getKeyword(), *ToQualifierOrErr, ToName, ToPack); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitDependentNameType(const DependentNameType *T) { |
| auto ToQualifierOrErr = import(T->getQualifier()); |
| if (!ToQualifierOrErr) |
| return ToQualifierOrErr.takeError(); |
| |
| IdentifierInfo *Name = Importer.Import(T->getIdentifier()); |
| |
| QualType Canon; |
| if (T != T->getCanonicalTypeInternal().getTypePtr()) { |
| if (ExpectedType TyOrErr = import(T->getCanonicalTypeInternal())) |
| Canon = (*TyOrErr).getCanonicalType(); |
| else |
| return TyOrErr.takeError(); |
| } |
| |
| return Importer.getToContext().getDependentNameType(T->getKeyword(), |
| *ToQualifierOrErr, |
| Name, Canon); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitObjCInterfaceType(const ObjCInterfaceType *T) { |
| Expected<ObjCInterfaceDecl *> ToDeclOrErr = import(T->getDecl()); |
| if (!ToDeclOrErr) |
| return ToDeclOrErr.takeError(); |
| |
| return Importer.getToContext().getObjCInterfaceType(*ToDeclOrErr); |
| } |
| |
| ExpectedType ASTNodeImporter::VisitObjCObjectType(const ObjCObjectType *T) { |
| ExpectedType ToBaseTypeOrErr = import(T->getBaseType()); |
| if (!ToBaseTypeOrErr) |
| return ToBaseTypeOrErr.takeError(); |
| |
| SmallVector<QualType, 4> TypeArgs; |
| for (auto TypeArg : T->getTypeArgsAsWritten()) { |
| if (ExpectedType TyOrErr = import(TypeArg)) |
| TypeArgs.push_back(*TyOrErr); |
| else |
| return TyOrErr.takeError(); |
| } |
| |
| SmallVector<ObjCProtocolDecl *, 4> Protocols; |
| for (auto *P : T->quals()) { |
| if (Expected<ObjCProtocolDecl *> ProtocolOrErr = import(P)) |
| Protocols.push_back(*ProtocolOrErr); |
| else |
| return ProtocolOrErr.takeError(); |
| |
| } |
| |
| return Importer.getToContext().getObjCObjectType(*ToBaseTypeOrErr, TypeArgs, |
| Protocols, |
| T->isKindOfTypeAsWritten()); |
| } |
| |
| ExpectedType |
| ASTNodeImporter::VisitObjCObjectPointerType(const ObjCObjectPointerType *T) { |
| ExpectedType ToPointeeTypeOrErr = import(T->getPointeeType()); |
| if (!ToPointeeTypeOrErr) |
| return ToPointeeTypeOrErr.takeError(); |
| |
| return Importer.getToContext().getObjCObjectPointerType(*ToPointeeTypeOrErr); |
| } |
| |
| //---------------------------------------------------------------------------- |
| // Import Declarations |
| //---------------------------------------------------------------------------- |
| Error ASTNodeImporter::ImportDeclParts( |
| NamedDecl *D, DeclContext *&DC, DeclContext *&LexicalDC, |
| DeclarationName &Name, NamedDecl *&ToD, SourceLocation &Loc) { |
| // Check if RecordDecl is in FunctionDecl parameters to avoid infinite loop. |
| // example: int struct_in_proto(struct data_t{int a;int b;} *d); |
| DeclContext *OrigDC = D->getDeclContext(); |
| FunctionDecl *FunDecl; |
| if (isa<RecordDecl>(D) && (FunDecl = dyn_cast<FunctionDecl>(OrigDC)) && |
| FunDecl->hasBody()) { |
| auto getLeafPointeeType = [](const Type *T) { |
| while (T->isPointerType() || T->isArrayType()) { |
| T = T->getPointeeOrArrayElementType(); |
| } |
| return T; |
| }; |
| for (const ParmVarDecl *P : FunDecl->parameters()) { |
| const Type *LeafT = |
| getLeafPointeeType(P->getType().getCanonicalType().getTypePtr()); |
| auto *RT = dyn_cast<RecordType>(LeafT); |
| if (RT && RT->getDecl() == D) { |
| Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) |
| << D->getDeclKindName(); |
| return make_error<ImportError>(ImportError::UnsupportedConstruct); |
| } |
| } |
| } |
| |
| // Import the context of this declaration. |
| if (Error Err = ImportDeclContext(D, DC, LexicalDC)) |
| return Err; |
| |
| // Import the name of this declaration. |
| if (Error Err = importInto(Name, D->getDeclName())) |
| return Err; |
| |
| // Import the location of this declaration. |
| if (Error Err = importInto(Loc, D->getLocation())) |
| return Err; |
| |
| ToD = cast_or_null<NamedDecl>(Importer.GetAlreadyImportedOrNull(D)); |
| if (ToD) |
| if (Error Err = ASTNodeImporter(*this).ImportDefinitionIfNeeded(D, ToD)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportDefinitionIfNeeded(Decl *FromD, Decl *ToD) { |
| if (!FromD) |
| return Error::success(); |
| |
| if (!ToD) |
| if (Error Err = importInto(ToD, FromD)) |
| return Err; |
| |
| if (RecordDecl *FromRecord = dyn_cast<RecordDecl>(FromD)) { |
| if (RecordDecl *ToRecord = cast<RecordDecl>(ToD)) { |
| if (FromRecord->getDefinition() && FromRecord->isCompleteDefinition() && |
| !ToRecord->getDefinition()) { |
| if (Error Err = ImportDefinition(FromRecord, ToRecord)) |
| return Err; |
| } |
| } |
| return Error::success(); |
| } |
| |
| if (EnumDecl *FromEnum = dyn_cast<EnumDecl>(FromD)) { |
| if (EnumDecl *ToEnum = cast<EnumDecl>(ToD)) { |
| if (FromEnum->getDefinition() && !ToEnum->getDefinition()) { |
| if (Error Err = ImportDefinition(FromEnum, ToEnum)) |
| return Err; |
| } |
| } |
| return Error::success(); |
| } |
| |
| return Error::success(); |
| } |
| |
| Error |
| ASTNodeImporter::ImportDeclarationNameLoc( |
| const DeclarationNameInfo &From, DeclarationNameInfo& To) { |
| // NOTE: To.Name and To.Loc are already imported. |
| // We only have to import To.LocInfo. |
| switch (To.getName().getNameKind()) { |
| case DeclarationName::Identifier: |
| case DeclarationName::ObjCZeroArgSelector: |
| case DeclarationName::ObjCOneArgSelector: |
| case DeclarationName::ObjCMultiArgSelector: |
| case DeclarationName::CXXUsingDirective: |
| case DeclarationName::CXXDeductionGuideName: |
| return Error::success(); |
| |
| case DeclarationName::CXXOperatorName: { |
| if (auto ToRangeOrErr = import(From.getCXXOperatorNameRange())) |
| To.setCXXOperatorNameRange(*ToRangeOrErr); |
| else |
| return ToRangeOrErr.takeError(); |
| return Error::success(); |
| } |
| case DeclarationName::CXXLiteralOperatorName: { |
| if (ExpectedSLoc LocOrErr = import(From.getCXXLiteralOperatorNameLoc())) |
| To.setCXXLiteralOperatorNameLoc(*LocOrErr); |
| else |
| return LocOrErr.takeError(); |
| return Error::success(); |
| } |
| case DeclarationName::CXXConstructorName: |
| case DeclarationName::CXXDestructorName: |
| case DeclarationName::CXXConversionFunctionName: { |
| if (auto ToTInfoOrErr = import(From.getNamedTypeInfo())) |
| To.setNamedTypeInfo(*ToTInfoOrErr); |
| else |
| return ToTInfoOrErr.takeError(); |
| return Error::success(); |
| } |
| } |
| llvm_unreachable("Unknown name kind."); |
| } |
| |
| Error |
| ASTNodeImporter::ImportDeclContext(DeclContext *FromDC, bool ForceImport) { |
| if (Importer.isMinimalImport() && !ForceImport) { |
| auto ToDCOrErr = Importer.ImportContext(FromDC); |
| return ToDCOrErr.takeError(); |
| } |
| |
| // We use strict error handling in case of records and enums, but not |
| // with e.g. namespaces. |
| // |
| // FIXME Clients of the ASTImporter should be able to choose an |
| // appropriate error handling strategy for their needs. For instance, |
| // they may not want to mark an entire namespace as erroneous merely |
| // because there is an ODR error with two typedefs. As another example, |
| // the client may allow EnumConstantDecls with same names but with |
| // different values in two distinct translation units. |
| bool AccumulateChildErrors = isa<TagDecl>(FromDC); |
| |
| Error ChildErrors = Error::success(); |
| for (auto *From : FromDC->decls()) { |
| ExpectedDecl ImportedOrErr = import(From); |
| if (!ImportedOrErr) { |
| if (AccumulateChildErrors) |
| ChildErrors = |
| joinErrors(std::move(ChildErrors), ImportedOrErr.takeError()); |
| else |
| consumeError(ImportedOrErr.takeError()); |
| } |
| } |
| |
| // We reorder declarations in RecordDecls because they may have another order |
| // in the "to" context than they have in the "from" context. This may happen |
| // e.g when we import a class like this: |
| // struct declToImport { |
| // int a = c + b; |
| // int b = 1; |
| // int c = 2; |
| // }; |
| // During the import of `a` we import first the dependencies in sequence, |
| // thus the order would be `c`, `b`, `a`. We will get the normal order by |
| // first removing the already imported members and then adding them in the |
| // order as they apper in the "from" context. |
| // |
| // Keeping field order is vital because it determines structure layout. |
| // |
| // Here and below, we cannot call field_begin() method and its callers on |
| // ToDC if it has an external storage. Calling field_begin() will |
| // automatically load all the fields by calling |
| // LoadFieldsFromExternalStorage(). LoadFieldsFromExternalStorage() would |
| // call ASTImporter::Import(). This is because the ExternalASTSource |
| // interface in LLDB is implemented by the means of the ASTImporter. However, |
| // calling an import at this point would result in an uncontrolled import, we |
| // must avoid that. |
| const auto *FromRD = dyn_cast<RecordDecl>(FromDC); |
| if (!FromRD) |
| return ChildErrors; |
| |
| auto ToDCOrErr = Importer.ImportContext(FromDC); |
| if (!ToDCOrErr) { |
| consumeError(std::move(ChildErrors)); |
| return ToDCOrErr.takeError(); |
| } |
| |
| DeclContext *ToDC = *ToDCOrErr; |
| // Remove all declarations, which may be in wrong order in the |
| // lexical DeclContext and then add them in the proper order. |
| for (auto *D : FromRD->decls()) { |
| if (isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || isa<FriendDecl>(D)) { |
| assert(D && "DC contains a null decl"); |
| Decl *ToD = Importer.GetAlreadyImportedOrNull(D); |
| // Remove only the decls which we successfully imported. |
| if (ToD) { |
| assert(ToDC == ToD->getLexicalDeclContext() && ToDC->containsDecl(ToD)); |
| // Remove the decl from its wrong place in the linked list. |
| ToDC->removeDecl(ToD); |
| // Add the decl to the end of the linked list. |
| // This time it will be at the proper place because the enclosing for |
| // loop iterates in the original (good) order of the decls. |
| ToDC->addDeclInternal(ToD); |
| } |
| } |
| } |
| |
| return ChildErrors; |
| } |
| |
| Error ASTNodeImporter::ImportDeclContext( |
| Decl *FromD, DeclContext *&ToDC, DeclContext *&ToLexicalDC) { |
| auto ToDCOrErr = Importer.ImportContext(FromD->getDeclContext()); |
| if (!ToDCOrErr) |
| return ToDCOrErr.takeError(); |
| ToDC = *ToDCOrErr; |
| |
| if (FromD->getDeclContext() != FromD->getLexicalDeclContext()) { |
| auto ToLexicalDCOrErr = Importer.ImportContext( |
| FromD->getLexicalDeclContext()); |
| if (!ToLexicalDCOrErr) |
| return ToLexicalDCOrErr.takeError(); |
| ToLexicalDC = *ToLexicalDCOrErr; |
| } else |
| ToLexicalDC = ToDC; |
| |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportImplicitMethods( |
| const CXXRecordDecl *From, CXXRecordDecl *To) { |
| assert(From->isCompleteDefinition() && To->getDefinition() == To && |
| "Import implicit methods to or from non-definition"); |
| |
| for (CXXMethodDecl *FromM : From->methods()) |
| if (FromM->isImplicit()) { |
| Expected<CXXMethodDecl *> ToMOrErr = import(FromM); |
| if (!ToMOrErr) |
| return ToMOrErr.takeError(); |
| } |
| |
| return Error::success(); |
| } |
| |
| static Error setTypedefNameForAnonDecl(TagDecl *From, TagDecl *To, |
| ASTImporter &Importer) { |
| if (TypedefNameDecl *FromTypedef = From->getTypedefNameForAnonDecl()) { |
| if (ExpectedDecl ToTypedefOrErr = Importer.Import(FromTypedef)) |
| To->setTypedefNameForAnonDecl(cast<TypedefNameDecl>(*ToTypedefOrErr)); |
| else |
| return ToTypedefOrErr.takeError(); |
| } |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportDefinition( |
| RecordDecl *From, RecordDecl *To, ImportDefinitionKind Kind) { |
| auto DefinitionCompleter = [To]() { |
| // There are cases in LLDB when we first import a class without its |
| // members. The class will have DefinitionData, but no members. Then, |
| // importDefinition is called from LLDB, which tries to get the members, so |
| // when we get here, the class already has the DefinitionData set, so we |
| // must unset the CompleteDefinition here to be able to complete again the |
| // definition. |
| To->setCompleteDefinition(false); |
| To->completeDefinition(); |
| }; |
| |
| if (To->getDefinition() || To->isBeingDefined()) { |
| if (Kind == IDK_Everything || |
| // In case of lambdas, the class already has a definition ptr set, but |
| // the contained decls are not imported yet. Also, isBeingDefined was |
| // set in CXXRecordDecl::CreateLambda. We must import the contained |
| // decls here and finish the definition. |
| (To->isLambda() && shouldForceImportDeclContext(Kind))) { |
| Error Result = ImportDeclContext(From, /*ForceImport=*/true); |
| // Finish the definition of the lambda, set isBeingDefined to false. |
| if (To->isLambda()) |
| DefinitionCompleter(); |
| return Result; |
| } |
| |
| return Error::success(); |
| } |
| |
| To->startDefinition(); |
| // Complete the definition even if error is returned. |
| // The RecordDecl may be already part of the AST so it is better to |
| // have it in complete state even if something is wrong with it. |
| auto DefinitionCompleterScopeExit = |
| llvm::make_scope_exit(DefinitionCompleter); |
| |
| if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) |
| return Err; |
| |
| // Add base classes. |
| auto *ToCXX = dyn_cast<CXXRecordDecl>(To); |
| auto *FromCXX = dyn_cast<CXXRecordDecl>(From); |
| if (ToCXX && FromCXX && ToCXX->dataPtr() && FromCXX->dataPtr()) { |
| |
| struct CXXRecordDecl::DefinitionData &ToData = ToCXX->data(); |
| struct CXXRecordDecl::DefinitionData &FromData = FromCXX->data(); |
| |
| #define FIELD(Name, Width, Merge) \ |
| ToData.Name = FromData.Name; |
| #include "clang/AST/CXXRecordDeclDefinitionBits.def" |
| |
| // Copy over the data stored in RecordDeclBits |
| ToCXX->setArgPassingRestrictions(FromCXX->getArgPassingRestrictions()); |
| |
| SmallVector<CXXBaseSpecifier *, 4> Bases; |
| for (const auto &Base1 : FromCXX->bases()) { |
| ExpectedType TyOrErr = import(Base1.getType()); |
| if (!TyOrErr) |
| return TyOrErr.takeError(); |
| |
| SourceLocation EllipsisLoc; |
| if (Base1.isPackExpansion()) { |
| if (ExpectedSLoc LocOrErr = import(Base1.getEllipsisLoc())) |
| EllipsisLoc = *LocOrErr; |
| else |
| return LocOrErr.takeError(); |
| } |
| |
| // Ensure that we have a definition for the base. |
| if (Error Err = |
| ImportDefinitionIfNeeded(Base1.getType()->getAsCXXRecordDecl())) |
| return Err; |
| |
| auto RangeOrErr = import(Base1.getSourceRange()); |
| if (!RangeOrErr) |
| return RangeOrErr.takeError(); |
| |
| auto TSIOrErr = import(Base1.getTypeSourceInfo()); |
| if (!TSIOrErr) |
| return TSIOrErr.takeError(); |
| |
| Bases.push_back( |
| new (Importer.getToContext()) CXXBaseSpecifier( |
| *RangeOrErr, |
| Base1.isVirtual(), |
| Base1.isBaseOfClass(), |
| Base1.getAccessSpecifierAsWritten(), |
| *TSIOrErr, |
| EllipsisLoc)); |
| } |
| if (!Bases.empty()) |
| ToCXX->setBases(Bases.data(), Bases.size()); |
| } |
| |
| if (shouldForceImportDeclContext(Kind)) |
| if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) |
| return Err; |
| |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportInitializer(VarDecl *From, VarDecl *To) { |
| if (To->getAnyInitializer()) |
| return Error::success(); |
| |
| Expr *FromInit = From->getInit(); |
| if (!FromInit) |
| return Error::success(); |
| |
| ExpectedExpr ToInitOrErr = import(FromInit); |
| if (!ToInitOrErr) |
| return ToInitOrErr.takeError(); |
| |
| To->setInit(*ToInitOrErr); |
| if (From->isInitKnownICE()) { |
| EvaluatedStmt *Eval = To->ensureEvaluatedStmt(); |
| Eval->CheckedICE = true; |
| Eval->IsICE = From->isInitICE(); |
| } |
| |
| // FIXME: Other bits to merge? |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportDefinition( |
| EnumDecl *From, EnumDecl *To, ImportDefinitionKind Kind) { |
| if (To->getDefinition() || To->isBeingDefined()) { |
| if (Kind == IDK_Everything) |
| return ImportDeclContext(From, /*ForceImport=*/true); |
| return Error::success(); |
| } |
| |
| To->startDefinition(); |
| |
| if (Error Err = setTypedefNameForAnonDecl(From, To, Importer)) |
| return Err; |
| |
| ExpectedType ToTypeOrErr = |
| import(Importer.getFromContext().getTypeDeclType(From)); |
| if (!ToTypeOrErr) |
| return ToTypeOrErr.takeError(); |
| |
| ExpectedType ToPromotionTypeOrErr = import(From->getPromotionType()); |
| if (!ToPromotionTypeOrErr) |
| return ToPromotionTypeOrErr.takeError(); |
| |
| if (shouldForceImportDeclContext(Kind)) |
| if (Error Err = ImportDeclContext(From, /*ForceImport=*/true)) |
| return Err; |
| |
| // FIXME: we might need to merge the number of positive or negative bits |
| // if the enumerator lists don't match. |
| To->completeDefinition(*ToTypeOrErr, *ToPromotionTypeOrErr, |
| From->getNumPositiveBits(), |
| From->getNumNegativeBits()); |
| return Error::success(); |
| } |
| |
| Error ASTNodeImporter::ImportTemplateArguments( |
| const TemplateArgument *FromArgs, unsigned NumFromArgs, |
| SmallVectorImpl<TemplateArgument> &ToArgs) { |
| for (unsigned I = 0; I != NumFromArgs; ++I) { |
| if (auto ToOrErr = import(FromArgs[I])) |
| ToArgs.push_back(*ToOrErr); |
| else |
| return ToOrErr.takeError(); |
| } |
| |
| return Error::success(); |
| } |
| |
| // FIXME: Do not forget to remove this and use only 'import'. |
| Expected<TemplateArgument> |
| ASTNodeImporter::ImportTemplateArgument(const TemplateArgument &From) { |
| return import(From); |
| } |
| |
| template <typename InContainerTy> |
| Error ASTNodeImporter::ImportTemplateArgumentListInfo( |
| const InContainerTy &Container, TemplateArgumentListInfo &ToTAInfo) { |
| for (const auto &FromLoc : Container) { |
| if (auto ToLocOrErr = import(FromLoc)) |
| ToTAInfo.addArgument(*ToLocOrErr); |
| else |
| return ToLocOrErr.takeError(); |
| } |
| return Error::success(); |
| } |
| |
| static StructuralEquivalenceKind |
| getStructuralEquivalenceKind(const ASTImporter &Importer) { |
| return Importer.isMinimalImport() ? StructuralEquivalenceKind::Minimal |
| : StructuralEquivalenceKind::Default; |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(Decl *From, Decl *To, bool Complain) { |
| StructuralEquivalenceContext Ctx( |
| Importer.getFromContext(), Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), |
| false, Complain); |
| return Ctx.IsEquivalent(From, To); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(RecordDecl *FromRecord, |
| RecordDecl *ToRecord, bool Complain) { |
| // Eliminate a potential failure point where we attempt to re-import |
| // something we're trying to import while completing ToRecord. |
| Decl *ToOrigin = Importer.GetOriginalDecl(ToRecord); |
| if (ToOrigin) { |
| auto *ToOriginRecord = dyn_cast<RecordDecl>(ToOrigin); |
| if (ToOriginRecord) |
| ToRecord = ToOriginRecord; |
| } |
| |
| StructuralEquivalenceContext Ctx(Importer.getFromContext(), |
| ToRecord->getASTContext(), |
| Importer.getNonEquivalentDecls(), |
| getStructuralEquivalenceKind(Importer), |
| false, Complain); |
| return Ctx.IsEquivalent(FromRecord, ToRecord); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(VarDecl *FromVar, VarDecl *ToVar, |
| bool Complain) { |
| StructuralEquivalenceContext Ctx( |
| Importer.getFromContext(), Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), |
| false, Complain); |
| return Ctx.IsEquivalent(FromVar, ToVar); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(EnumDecl *FromEnum, EnumDecl *ToEnum) { |
| // Eliminate a potential failure point where we attempt to re-import |
| // something we're trying to import while completing ToEnum. |
| if (Decl *ToOrigin = Importer.GetOriginalDecl(ToEnum)) |
| if (auto *ToOriginEnum = dyn_cast<EnumDecl>(ToOrigin)) |
| ToEnum = ToOriginEnum; |
| |
| StructuralEquivalenceContext Ctx( |
| Importer.getFromContext(), Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer)); |
| return Ctx.IsEquivalent(FromEnum, ToEnum); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(FunctionTemplateDecl *From, |
| FunctionTemplateDecl *To) { |
| StructuralEquivalenceContext Ctx( |
| Importer.getFromContext(), Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), |
| false, false); |
| return Ctx.IsEquivalent(From, To); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(FunctionDecl *From, FunctionDecl *To) { |
| StructuralEquivalenceContext Ctx( |
| Importer.getFromContext(), Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), getStructuralEquivalenceKind(Importer), |
| false, false); |
| return Ctx.IsEquivalent(From, To); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, |
| EnumConstantDecl *ToEC) { |
| const llvm::APSInt &FromVal = FromEC->getInitVal(); |
| const llvm::APSInt &ToVal = ToEC->getInitVal(); |
| |
| return FromVal.isSigned() == ToVal.isSigned() && |
| FromVal.getBitWidth() == ToVal.getBitWidth() && |
| FromVal == ToVal; |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(ClassTemplateDecl *From, |
| ClassTemplateDecl *To) { |
| StructuralEquivalenceContext Ctx(Importer.getFromContext(), |
| Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), |
| getStructuralEquivalenceKind(Importer)); |
| return Ctx.IsEquivalent(From, To); |
| } |
| |
| bool ASTNodeImporter::IsStructuralMatch(VarTemplateDecl *From, |
| VarTemplateDecl *To) { |
| StructuralEquivalenceContext Ctx(Importer.getFromContext(), |
| Importer.getToContext(), |
| Importer.getNonEquivalentDecls(), |
| getStructuralEquivalenceKind(Importer)); |
| return Ctx.IsEquivalent(From, To); |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitDecl(Decl *D) { |
| Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) |
| << D->getDeclKindName(); |
| return make_error<ImportError>(ImportError::UnsupportedConstruct); |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitImportDecl(ImportDecl *D) { |
| Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) |
| << D->getDeclKindName(); |
| return make_error<ImportError>(ImportError::UnsupportedConstruct); |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitEmptyDecl(EmptyDecl *D) { |
| // Import the context of this declaration. |
| DeclContext *DC, *LexicalDC; |
| if (Error Err = ImportDeclContext(D, DC, LexicalDC)) |
| return std::move(Err); |
| |
| // Import the location of this declaration. |
| ExpectedSLoc LocOrErr = import(D->getLocation()); |
| if (!LocOrErr) |
| return LocOrErr.takeError(); |
| |
| EmptyDecl *ToD; |
| if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), DC, *LocOrErr)) |
| return ToD; |
| |
| ToD->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToD); |
| return ToD; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitTranslationUnitDecl(TranslationUnitDecl *D) { |
| TranslationUnitDecl *ToD = |
| Importer.getToContext().getTranslationUnitDecl(); |
| |
| Importer.MapImported(D, ToD); |
| |
| return ToD; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitAccessSpecDecl(AccessSpecDecl *D) { |
| ExpectedSLoc LocOrErr = import(D->getLocation()); |
| if (!LocOrErr) |
| return LocOrErr.takeError(); |
| auto ColonLocOrErr = import(D->getColonLoc()); |
| if (!ColonLocOrErr) |
| return ColonLocOrErr.takeError(); |
| |
| // Import the context of this declaration. |
| auto DCOrErr = Importer.ImportContext(D->getDeclContext()); |
| if (!DCOrErr) |
| return DCOrErr.takeError(); |
| DeclContext *DC = *DCOrErr; |
| |
| AccessSpecDecl *ToD; |
| if (GetImportedOrCreateDecl(ToD, D, Importer.getToContext(), D->getAccess(), |
| DC, *LocOrErr, *ColonLocOrErr)) |
| return ToD; |
| |
| // Lexical DeclContext and Semantic DeclContext |
| // is always the same for the accessSpec. |
| ToD->setLexicalDeclContext(DC); |
| DC->addDeclInternal(ToD); |
| |
| return ToD; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitStaticAssertDecl(StaticAssertDecl *D) { |
| auto DCOrErr = Importer.ImportContext(D->getDeclContext()); |
| if (!DCOrErr) |
| return DCOrErr.takeError(); |
| DeclContext *DC = *DCOrErr; |
| DeclContext *LexicalDC = DC; |
| |
| SourceLocation ToLocation, ToRParenLoc; |
| Expr *ToAssertExpr; |
| StringLiteral *ToMessage; |
| if (auto Imp = importSeq( |
| D->getLocation(), D->getAssertExpr(), D->getMessage(), D->getRParenLoc())) |
| std::tie(ToLocation, ToAssertExpr, ToMessage, ToRParenLoc) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| StaticAssertDecl *ToD; |
| if (GetImportedOrCreateDecl( |
| ToD, D, Importer.getToContext(), DC, ToLocation, ToAssertExpr, ToMessage, |
| ToRParenLoc, D->isFailed())) |
| return ToD; |
| |
| ToD->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToD); |
| return ToD; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitNamespaceDecl(NamespaceDecl *D) { |
| // Import the major distinguishing characteristics of this namespace. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *ToD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) |
| return std::move(Err); |
| if (ToD) |
| return ToD; |
| |
| NamespaceDecl *MergeWithNamespace = nullptr; |
| if (!Name) { |
| // This is an anonymous namespace. Adopt an existing anonymous |
| // namespace if we can. |
| // FIXME: Not testable. |
| if (auto *TU = dyn_cast<TranslationUnitDecl>(DC)) |
| MergeWithNamespace = TU->getAnonymousNamespace(); |
| else |
| MergeWithNamespace = cast<NamespaceDecl>(DC)->getAnonymousNamespace(); |
| } else { |
| SmallVector<NamedDecl *, 4> ConflictingDecls; |
| auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); |
| for (auto *FoundDecl : FoundDecls) { |
| if (!FoundDecl->isInIdentifierNamespace(Decl::IDNS_Namespace)) |
| continue; |
| |
| if (auto *FoundNS = dyn_cast<NamespaceDecl>(FoundDecl)) { |
| MergeWithNamespace = FoundNS; |
| ConflictingDecls.clear(); |
| break; |
| } |
| |
| ConflictingDecls.push_back(FoundDecl); |
| } |
| |
| if (!ConflictingDecls.empty()) { |
| ExpectedName NameOrErr = Importer.HandleNameConflict( |
| Name, DC, Decl::IDNS_Namespace, ConflictingDecls.data(), |
| ConflictingDecls.size()); |
| if (NameOrErr) |
| Name = NameOrErr.get(); |
| else |
| return NameOrErr.takeError(); |
| } |
| } |
| |
| ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); |
| if (!BeginLocOrErr) |
| return BeginLocOrErr.takeError(); |
| |
| // Create the "to" namespace, if needed. |
| NamespaceDecl *ToNamespace = MergeWithNamespace; |
| if (!ToNamespace) { |
| if (GetImportedOrCreateDecl( |
| ToNamespace, D, Importer.getToContext(), DC, D->isInline(), |
| *BeginLocOrErr, Loc, Name.getAsIdentifierInfo(), |
| /*PrevDecl=*/nullptr)) |
| return ToNamespace; |
| ToNamespace->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToNamespace); |
| |
| // If this is an anonymous namespace, register it as the anonymous |
| // namespace within its context. |
| if (!Name) { |
| if (auto *TU = dyn_cast<TranslationUnitDecl>(DC)) |
| TU->setAnonymousNamespace(ToNamespace); |
| else |
| cast<NamespaceDecl>(DC)->setAnonymousNamespace(ToNamespace); |
| } |
| } |
| Importer.MapImported(D, ToNamespace); |
| |
| if (Error Err = ImportDeclContext(D)) |
| return std::move(Err); |
| |
| return ToNamespace; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitNamespaceAliasDecl(NamespaceAliasDecl *D) { |
| // Import the major distinguishing characteristics of this namespace. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *LookupD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, LookupD, Loc)) |
| return std::move(Err); |
| if (LookupD) |
| return LookupD; |
| |
| // NOTE: No conflict resolution is done for namespace aliases now. |
| |
| SourceLocation ToNamespaceLoc, ToAliasLoc, ToTargetNameLoc; |
| NestedNameSpecifierLoc ToQualifierLoc; |
| NamespaceDecl *ToNamespace; |
| if (auto Imp = importSeq( |
| D->getNamespaceLoc(), D->getAliasLoc(), D->getQualifierLoc(), |
| D->getTargetNameLoc(), D->getNamespace())) |
| std::tie( |
| ToNamespaceLoc, ToAliasLoc, ToQualifierLoc, ToTargetNameLoc, |
| ToNamespace) = *Imp; |
| else |
| return Imp.takeError(); |
| IdentifierInfo *ToIdentifier = Importer.Import(D->getIdentifier()); |
| |
| NamespaceAliasDecl *ToD; |
| if (GetImportedOrCreateDecl( |
| ToD, D, Importer.getToContext(), DC, ToNamespaceLoc, ToAliasLoc, |
| ToIdentifier, ToQualifierLoc, ToTargetNameLoc, ToNamespace)) |
| return ToD; |
| |
| ToD->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToD); |
| |
| return ToD; |
| } |
| |
| ExpectedDecl |
| ASTNodeImporter::VisitTypedefNameDecl(TypedefNameDecl *D, bool IsAlias) { |
| // Import the major distinguishing characteristics of this typedef. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *ToD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) |
| return std::move(Err); |
| if (ToD) |
| return ToD; |
| |
| // If this typedef is not in block scope, determine whether we've |
| // seen a typedef with the same name (that we can merge with) or any |
| // other entity by that name (which name lookup could conflict with). |
| // Note: Repeated typedefs are not valid in C99: |
| // 'typedef int T; typedef int T;' is invalid |
| // We do not care about this now. |
| if (!DC->isFunctionOrMethod()) { |
| SmallVector<NamedDecl *, 4> ConflictingDecls; |
| unsigned IDNS = Decl::IDNS_Ordinary; |
| auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); |
| for (auto *FoundDecl : FoundDecls) { |
| if (!FoundDecl->isInIdentifierNamespace(IDNS)) |
| continue; |
| if (auto *FoundTypedef = dyn_cast<TypedefNameDecl>(FoundDecl)) { |
| if (!hasSameVisibilityContext(FoundTypedef, D)) |
| continue; |
| |
| QualType FromUT = D->getUnderlyingType(); |
| QualType FoundUT = FoundTypedef->getUnderlyingType(); |
| if (Importer.IsStructurallyEquivalent(FromUT, FoundUT)) { |
| // If the "From" context has a complete underlying type but we |
| // already have a complete underlying type then return with that. |
| if (!FromUT->isIncompleteType() && !FoundUT->isIncompleteType()) |
| return Importer.MapImported(D, FoundTypedef); |
| // FIXME Handle redecl chain. When you do that make consistent changes |
| // in ASTImporterLookupTable too. |
| } else { |
| ConflictingDecls.push_back(FoundDecl); |
| } |
| } |
| } |
| |
| if (!ConflictingDecls.empty()) { |
| ExpectedName NameOrErr = Importer.HandleNameConflict( |
| Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); |
| if (NameOrErr) |
| Name = NameOrErr.get(); |
| else |
| return NameOrErr.takeError(); |
| } |
| } |
| |
| QualType ToUnderlyingType; |
| TypeSourceInfo *ToTypeSourceInfo; |
| SourceLocation ToBeginLoc; |
| if (auto Imp = importSeq( |
| D->getUnderlyingType(), D->getTypeSourceInfo(), D->getBeginLoc())) |
| std::tie(ToUnderlyingType, ToTypeSourceInfo, ToBeginLoc) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| // Create the new typedef node. |
| // FIXME: ToUnderlyingType is not used. |
| TypedefNameDecl *ToTypedef; |
| if (IsAlias) { |
| if (GetImportedOrCreateDecl<TypeAliasDecl>( |
| ToTypedef, D, Importer.getToContext(), DC, ToBeginLoc, Loc, |
| Name.getAsIdentifierInfo(), ToTypeSourceInfo)) |
| return ToTypedef; |
| } else if (GetImportedOrCreateDecl<TypedefDecl>( |
| ToTypedef, D, Importer.getToContext(), DC, ToBeginLoc, Loc, |
| Name.getAsIdentifierInfo(), ToTypeSourceInfo)) |
| return ToTypedef; |
| |
| ToTypedef->setAccess(D->getAccess()); |
| ToTypedef->setLexicalDeclContext(LexicalDC); |
| |
| // Templated declarations should not appear in DeclContext. |
| TypeAliasDecl *FromAlias = IsAlias ? cast<TypeAliasDecl>(D) : nullptr; |
| if (!FromAlias || !FromAlias->getDescribedAliasTemplate()) |
| LexicalDC->addDeclInternal(ToTypedef); |
| |
| return ToTypedef; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitTypedefDecl(TypedefDecl *D) { |
| return VisitTypedefNameDecl(D, /*IsAlias=*/false); |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitTypeAliasDecl(TypeAliasDecl *D) { |
| return VisitTypedefNameDecl(D, /*IsAlias=*/true); |
| } |
| |
| ExpectedDecl |
| ASTNodeImporter::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { |
| // Import the major distinguishing characteristics of this typedef. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *FoundD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, FoundD, Loc)) |
| return std::move(Err); |
| if (FoundD) |
| return FoundD; |
| |
| // If this typedef is not in block scope, determine whether we've |
| // seen a typedef with the same name (that we can merge with) or any |
| // other entity by that name (which name lookup could conflict with). |
| if (!DC->isFunctionOrMethod()) { |
| SmallVector<NamedDecl *, 4> ConflictingDecls; |
| unsigned IDNS = Decl::IDNS_Ordinary; |
| auto FoundDecls = Importer.findDeclsInToCtx(DC, Name); |
| for (auto *FoundDecl : FoundDecls) { |
| if (!FoundDecl->isInIdentifierNamespace(IDNS)) |
| continue; |
| if (auto *FoundAlias = dyn_cast<TypeAliasTemplateDecl>(FoundDecl)) |
| return Importer.MapImported(D, FoundAlias); |
| ConflictingDecls.push_back(FoundDecl); |
| } |
| |
| if (!ConflictingDecls.empty()) { |
| ExpectedName NameOrErr = Importer.HandleNameConflict( |
| Name, DC, IDNS, ConflictingDecls.data(), ConflictingDecls.size()); |
| if (NameOrErr) |
| Name = NameOrErr.get(); |
| else |
| return NameOrErr.takeError(); |
| } |
| } |
| |
| TemplateParameterList *ToTemplateParameters; |
| TypeAliasDecl *ToTemplatedDecl; |
| if (auto Imp = importSeq(D->getTemplateParameters(), D->getTemplatedDecl())) |
| std::tie(ToTemplateParameters, ToTemplatedDecl) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| TypeAliasTemplateDecl *ToAlias; |
| if (GetImportedOrCreateDecl(ToAlias, D, Importer.getToContext(), DC, Loc, |
| Name, ToTemplateParameters, ToTemplatedDecl)) |
| return ToAlias; |
| |
| ToTemplatedDecl->setDescribedAliasTemplate(ToAlias); |
| |
| ToAlias->setAccess(D->getAccess()); |
| ToAlias->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToAlias); |
| return ToAlias; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitLabelDecl(LabelDecl *D) { |
| // Import the major distinguishing characteristics of this label. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *ToD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) |
| return std::move(Err); |
| if (ToD) |
| return ToD; |
| |
| assert(LexicalDC->isFunctionOrMethod()); |
| |
| LabelDecl *ToLabel; |
| if (D->isGnuLocal()) { |
| ExpectedSLoc BeginLocOrErr = import(D->getBeginLoc()); |
| if (!BeginLocOrErr) |
| return BeginLocOrErr.takeError(); |
| if (GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, Loc, |
| Name.getAsIdentifierInfo(), *BeginLocOrErr)) |
| return ToLabel; |
| |
| } else { |
| if (GetImportedOrCreateDecl(ToLabel, D, Importer.getToContext(), DC, Loc, |
| Name.getAsIdentifierInfo())) |
| return ToLabel; |
| |
| } |
| |
| Expected<LabelStmt *> ToStmtOrErr = import(D->getStmt()); |
| if (!ToStmtOrErr) |
| return ToStmtOrErr.takeError(); |
| |
| ToLabel->setStmt(*ToStmtOrErr); |
| ToLabel->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(ToLabel); |
| return ToLabel; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitEnumDecl(EnumDecl *D) { |
| // Import the major distinguishing characteristics of this enum. |
| DeclContext *DC, *LexicalDC; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *ToD; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) |
| return std::move(Err); |
| if (ToD) |
| return ToD; |
| |
| // Figure out what enum name we're looking for. |
| unsigned IDNS = Decl::IDNS_Tag; |
| DeclarationName SearchName = Name; |
| if (!SearchName && D->getTypedefNameForAnonDecl()) { |
| if (Error Err = importInto( |
| SearchName, D->getTypedefNameForAnonDecl()->getDeclName())) |
| return std::move(Err); |
| IDNS = Decl::IDNS_Ordinary; |
| } else if (Importer.getToContext().getLangOpts().CPlusPlus) |
| IDNS |= Decl::IDNS_Ordinary; |
| |
| // We may already have an enum of the same name; try to find and match it. |
| if (!DC->isFunctionOrMethod() && SearchName) { |
| SmallVector<NamedDecl *, 4> ConflictingDecls; |
| auto FoundDecls = |
| Importer.findDeclsInToCtx(DC, SearchName); |
| for (auto *FoundDecl : FoundDecls) { |
| if (!FoundDecl->isInIdentifierNamespace(IDNS)) |
| continue; |
| |
| if (auto *Typedef = dyn_cast<TypedefNameDecl>(FoundDecl)) { |
| if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) |
| FoundDecl = Tag->getDecl(); |
| } |
| |
| if (auto *FoundEnum = dyn_cast<EnumDecl>(FoundDecl)) { |
| if (!hasSameVisibilityContext(FoundEnum, D)) |
| continue; |
| if (IsStructuralMatch(D, FoundEnum)) |
| return Importer.MapImported(D, FoundEnum); |
| ConflictingDecls.push_back(FoundDecl); |
| } |
| } |
| |
| if (!ConflictingDecls.empty()) { |
| ExpectedName NameOrErr = Importer.HandleNameConflict( |
| SearchName, DC, IDNS, ConflictingDecls.data(), |
| ConflictingDecls.size()); |
| if (NameOrErr) |
| Name = NameOrErr.get(); |
| else |
| return NameOrErr.takeError(); |
| } |
| } |
| |
| SourceLocation ToBeginLoc; |
| NestedNameSpecifierLoc ToQualifierLoc; |
| QualType ToIntegerType; |
| if (auto Imp = importSeq( |
| D->getBeginLoc(), D->getQualifierLoc(), D->getIntegerType())) |
| std::tie(ToBeginLoc, ToQualifierLoc, ToIntegerType) = *Imp; |
| else |
| return Imp.takeError(); |
| |
| // Create the enum declaration. |
| EnumDecl *D2; |
| if (GetImportedOrCreateDecl( |
| D2, D, Importer.getToContext(), DC, ToBeginLoc, |
| Loc, Name.getAsIdentifierInfo(), nullptr, D->isScoped(), |
| D->isScopedUsingClassTag(), D->isFixed())) |
| return D2; |
| |
| D2->setQualifierInfo(ToQualifierLoc); |
| D2->setIntegerType(ToIntegerType); |
| D2->setAccess(D->getAccess()); |
| D2->setLexicalDeclContext(LexicalDC); |
| LexicalDC->addDeclInternal(D2); |
| |
| // Import the definition |
| if (D->isCompleteDefinition()) |
| if (Error Err = ImportDefinition(D, D2)) |
| return std::move(Err); |
| |
| return D2; |
| } |
| |
| ExpectedDecl ASTNodeImporter::VisitRecordDecl(RecordDecl *D) { |
| bool IsFriendTemplate = false; |
| if (auto *DCXX = dyn_cast<CXXRecordDecl>(D)) { |
| IsFriendTemplate = |
| DCXX->getDescribedClassTemplate() && |
| DCXX->getDescribedClassTemplate()->getFriendObjectKind() != |
| Decl::FOK_None; |
| } |
| |
| // Import the major distinguishing characteristics of this record. |
| DeclContext *DC = nullptr, *LexicalDC = nullptr; |
| DeclarationName Name; |
| SourceLocation Loc; |
| NamedDecl *ToD = nullptr; |
| if (Error Err = ImportDeclParts(D, DC, LexicalDC, Name, ToD, Loc)) |
| return std::move(Err); |
| if (ToD) |
| return ToD; |
| |
| // Figure out what structure name we're looking for. |
| unsigned IDNS = Decl::IDNS_Tag; |
| DeclarationName SearchName = Name; |
| if (!SearchName && D->getTypedefNameForAnonDecl()) { |
| if (Error Err = importInto( |
| SearchName, D->getTypedefNameForAnonDecl()->getDeclName())) |
| return std::move(Err); |
| IDNS = Decl::IDNS_Ordinary; |
| } else if (Importer.getToContext().getLangOpts().CPlusPlus) |
| IDNS |= Decl::IDNS_Ordinary | Decl::IDNS_TagFriend; |
| |
| // We may already have a record of the same name; try to find and match it. |
| RecordDecl *PrevDecl = nullptr; |
| if (!DC->isFunctionOrMethod() && !D->isLambda()) { |
| SmallVector<NamedDecl *, 4> ConflictingDecls; |
| auto FoundDecls = |
| Importer.findDeclsInToCtx(DC, SearchName); |
| if (!FoundDecls.empty()) { |
| // We're going to have to compare D against potentially conflicting Decls, |
| // so complete it. |
| if (D->hasExternalLexicalStorage() && !D->isCompleteDefinition()) |
| D->getASTContext().getExternalSource()->CompleteType(D); |
| } |
| |
| for (auto *FoundDecl : FoundDecls) { |
| if (!FoundDecl->isInIdentifierNamespace(IDNS)) |
| continue; |
| |
| Decl *Found = FoundDecl; |
| if (auto *Typedef = dyn_cast<TypedefNameDecl>(Found)) { |
| if (const auto *Tag = Typedef->getUnderlyingType()->getAs<TagType>()) |
| Found = Tag->getDecl(); |
| } |
| |
| if (auto *FoundRecord = dyn_cast<RecordDecl>(Found)) { |
| // Do not emit false positive diagnostic in case of unnamed |
| // struct/union and in case of anonymous structs. Would be false |
| // because there may be several anonymous/unnamed structs in a class. |
| // E.g. these are both valid: |
| // struct A { // unnamed structs |
| // struct { struct A *next; } entry0; |
| // struct { struct A *next; } entry1; |
| // }; |
| // struct X { struct { int a; }; struct { int b; }; }; // anon structs |
| if (!SearchName) |
| if (!IsStructuralMatch(D, FoundRecord, false)) |
| continue; |
| |
| if (!hasSameVisibilityContext(FoundRecord, D)) |
| continue; |
| |
|