diff --git a/clang/lib/AST/ASTImporter.cpp b/clang/lib/AST/ASTImporter.cpp --- a/clang/lib/AST/ASTImporter.cpp +++ b/clang/lib/AST/ASTImporter.cpp @@ -42,6 +42,7 @@ #include "clang/AST/TemplateName.h" #include "clang/AST/Type.h" #include "clang/AST/TypeLoc.h" +#include "clang/AST/TypeLocVisitor.h" #include "clang/AST/TypeVisitor.h" #include "clang/AST/UnresolvedSet.h" #include "clang/Basic/Builtins.h" @@ -695,6 +696,8 @@ // that type is declared inside the body of the function. // E.g. auto f() { struct X{}; return X(); } bool hasAutoReturnTypeDeclaredInside(FunctionDecl *D); + + friend class TypeLocImporter; }; template @@ -3275,6 +3278,15 @@ FromReturnTy, FromFPT->getParamTypes(), FromEPI); } + // Import the function parameters. + SmallVector Parameters; + for (auto P : D->parameters()) { + if (Expected ToPOrErr = import(P)) + Parameters.push_back(*ToPOrErr); + else + return ToPOrErr.takeError(); + } + QualType T; TypeSourceInfo *TInfo; SourceLocation ToInnerLocStart, ToEndLoc; @@ -3288,15 +3300,6 @@ else return Imp.takeError(); - // Import the function parameters. - SmallVector Parameters; - for (auto P : D->parameters()) { - if (Expected ToPOrErr = import(P)) - Parameters.push_back(*ToPOrErr); - else - return ToPOrErr.takeError(); - } - // Create the imported function. FunctionDecl *ToFunction = nullptr; if (auto *FromConstructor = dyn_cast(D)) { @@ -3402,16 +3405,6 @@ } ToFunction->setParams(Parameters); - // We need to complete creation of FunctionProtoTypeLoc manually with setting - // params it refers to. - if (TInfo) { - if (auto ProtoLoc = - TInfo->getTypeLoc().IgnoreParens().getAs()) { - for (unsigned I = 0, N = Parameters.size(); I != N; ++I) - ProtoLoc.setParam(I, Parameters[I]); - } - } - // Import the describing template function, if any. if (FromFT) { auto ToFTOrErr = import(FromFT); @@ -8111,20 +8104,305 @@ return ToContext.getQualifiedType(*ToTOrErr, FromT.getLocalQualifiers()); } +namespace clang { + +#define IMPORT_TYPE_LOC_OR_RETURN_ERROR(NAME) \ + if (auto ImpOrErr = Importer.Import(From.get##NAME())) \ + To.set##NAME(*ImpOrErr); \ + else \ + return ImpOrErr.takeError(); + +// Import TypeLoc information. +// TypeLocReader in ASTReader.cpp gives hints about what to import. +// (At some ObjC types not every existing location is copied.) +class TypeLocImporter : public TypeLocVisitor { + ASTImporter &Importer; + TypeLoc ToL; + +public: + TypeLocImporter(ASTImporter &Importer, TypeLoc ToL) + : Importer(Importer), ToL(ToL) {} + + Error VisitTypeLoc(TypeLoc From) { + // The visitor does not call directly VisitTypeSpecTypeLoc, because that is + // not a leaf node in the hierarchy (i.e. there is no such enum value in + // TypeNodes.inc). + if (auto FTS = From.getAs()) + return VisitTypeSpecTypeLoc(FTS); + return Error::success(); + } + + Error VisitTypeSpecTypeLoc(TypeSpecTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(NameLoc); + return Error::success(); + } + + Error VisitBuiltinTypeLoc(BuiltinTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(BuiltinLoc); + return Error::success(); + } + + Error VisitParenTypeLoc(ParenTypeLoc From) { + auto To = ToL.castAs(); + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RParenLoc); + + return Error::success(); + } + + Error VisitPointerTypeLoc(PointerTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(StarLoc); + return Error::success(); + } + + Error VisitBlockPointerTypeLoc(BlockPointerTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(CaretLoc); + return Error::success(); + } + + Error VisitMemberPointerTypeLoc(MemberPointerTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(StarLoc); + return Error::success(); + } + + Error VisitObjCObjectPointerTypeLoc(ObjCObjectPointerTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(StarLoc); + return Error::success(); + } + + Error VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(AmpLoc); + return Error::success(); + } + + Error VisitRValueReferenceTypeLoc(RValueReferenceTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(AmpAmpLoc); + return Error::success(); + } + + Error VisitFunctionTypeLoc(FunctionTypeLoc From) { + auto To = ToL.castAs(); + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LocalRangeBegin); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LocalRangeEnd); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ExceptionSpecRange); + + for (unsigned I = 0; I < From.getNumParams(); ++I) + To.setParam( + I, cast_or_null( + // In the case of importing a lambda CXXRecordDecl the + // parameter had not been imported yet. That will be imported + // later when the lambda's operator() is imported. + Importer.GetAlreadyImportedOrNull(From.getParam(I)))); + + return Error::success(); + } + + Error VisitArrayTypeLoc(ArrayTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LBracketLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RBracketLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(SizeExpr); + return Error::success(); + } + + Error VisitTemplateSpecializationTypeLoc(TemplateSpecializationTypeLoc From) { + auto To = ToL.castAs(); + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TemplateKeywordLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TemplateNameLoc); + + ASTNodeImporter NodeImporter(Importer); + for (unsigned I = 0; I < From.getNumArgs(); ++I) { + if (Expected TAL = + NodeImporter.import(From.getArgLoc(I))) + To.setArgLocInfo(I, TAL->getLocInfo()); + else + return TAL.takeError(); + } + + return Error::success(); + } + + Error VisitDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(AttrNameLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(AttrOperandParensRange); + // FIXME: Import other things? + return Error::success(); + } + + Error VisitTypeOfTypeLoc(TypeOfTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(UnderlyingTInfo); + return Error::success(); + } + + Error VisitUnaryTransformTypeLoc(UnaryTransformTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(KWLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(UnderlyingTInfo); + return Error::success(); + } + + Error VisitDeducedTemplateSpecializationTypeLoc( + DeducedTemplateSpecializationTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TemplateNameLoc); + return Error::success(); + } + + Error VisitElaboratedTypeLoc(ElaboratedTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ElaboratedKeywordLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(QualifierLoc); + return Error::success(); + } + + Error VisitDependentNameTypeLoc(DependentNameTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ElaboratedKeywordLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(QualifierLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(NameLoc); + return Error::success(); + } + + Error VisitDependentTemplateSpecializationTypeLoc( + DependentTemplateSpecializationTypeLoc From) { + auto To = ToL.castAs(); + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ElaboratedKeywordLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(QualifierLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TemplateKeywordLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TemplateNameLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RAngleLoc); + + ASTNodeImporter NodeImporter(Importer); + for (unsigned I = 0; I < From.getNumArgs(); ++I) { + if (Expected TAL = + NodeImporter.import(From.getArgLoc(I))) + To.setArgLocInfo(I, TAL->getLocInfo()); + else + return TAL.takeError(); + } + + return Error::success(); + } + + Error VisitPackExpansionTypeLoc(PackExpansionTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(EllipsisLoc); + return Error::success(); + } + + Error VisitAtomicTypeLoc(AtomicTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(KWLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(LParenLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(RParenLoc); + return Error::success(); + } + + Error VisitPipeTypeLoc(PipeTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(KWLoc); + return Error::success(); + } + + Error VisitObjCTypeParamTypeLoc(ObjCTypeParamTypeLoc From) { + auto To = ToL.castAs(); + if (From.getNumProtocols()) { + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ProtocolLAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ProtocolRAngleLoc); + for (unsigned I = 0; I < From.getNumProtocols(); ++I) { + if (ExpectedSLoc L = Importer.Import(From.getProtocolLoc(I))) + To.setProtocolLoc(I, *L); + else + return L.takeError(); + } + } + return Error::success(); + } + + Error VisitObjCObjectTypeLoc(ObjCObjectTypeLoc From) { + auto To = ToL.castAs(); + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TypeArgsLAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(TypeArgsRAngleLoc); + + for (unsigned I = 0; I < From.getNumTypeArgs(); ++I) { + if (Expected TSI = + Importer.Import(From.getTypeArgTInfo(I))) + To.setTypeArgTInfo(I, *TSI); + else + return TSI.takeError(); + } + + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ProtocolLAngleLoc); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(ProtocolRAngleLoc); + + for (unsigned I = 0; I < From.getNumProtocols(); ++I) { + if (ExpectedSLoc L = Importer.Import(From.getProtocolLoc(I))) + To.setProtocolLoc(I, *L); + else + return L.takeError(); + } + + To.setHasBaseTypeAsWritten(From.hasBaseTypeAsWritten()); + + return Error::success(); + } + + Error VisitObjCInterfaceTypeLoc(ObjCInterfaceTypeLoc From) { + auto To = ToL.castAs(); + IMPORT_TYPE_LOC_OR_RETURN_ERROR(NameLoc); + return Error::success(); + } + +}; + +#undef IMPORT_TYPE_LOC_OR_RETURN_ERROR + +} // namespace clang + Expected ASTImporter::Import(TypeSourceInfo *FromTSI) { if (!FromTSI) return FromTSI; - // FIXME: For now we just create a "trivial" type source info based - // on the type and a single location. Implement a real version of this. ExpectedType TOrErr = Import(FromTSI->getType()); if (!TOrErr) return TOrErr.takeError(); - ExpectedSLoc BeginLocOrErr = Import(FromTSI->getTypeLoc().getBeginLoc()); - if (!BeginLocOrErr) - return BeginLocOrErr.takeError(); - return ToContext.getTrivialTypeSourceInfo(*TOrErr, *BeginLocOrErr); + TypeSourceInfo *ToTSI = ToContext.CreateTypeSourceInfo(*TOrErr); + + TypeLoc FromL = FromTSI->getTypeLoc(); + TypeLoc ToL = ToTSI->getTypeLoc(); + while (FromL) { + assert(ToL && "Not consistent TypeSourceInfo"); + TypeLocImporter Importer(*this, ToL); + if (Error Err = Importer.Visit(FromL)) + return std::move(Err); + FromL = FromL.getNextTypeLoc(); + ToL = ToL.getNextTypeLoc(); + } + + return ToTSI; } Expected ASTImporter::Import(const Attr *FromAttr) { diff --git a/clang/unittests/AST/ASTImporterTest.cpp b/clang/unittests/AST/ASTImporterTest.cpp --- a/clang/unittests/AST/ASTImporterTest.cpp +++ b/clang/unittests/AST/ASTImporterTest.cpp @@ -5845,6 +5845,53 @@ EXPECT_TRUE(isa(To->getReturnType())); } +struct ImportTypeLoc : ASTImporterOptionSpecificTestBase {}; + +TEST_P(ImportTypeLoc, Function) { + Decl *FromTU = getTuDecl( + R"( + int f(int p) { + return 1; + } + )", + Lang_CXX11, "input0.cc"); + FunctionDecl *FromF = FirstDeclMatcher().match( + FromTU, functionDecl(hasName("f"))); + FunctionDecl *ToF = Import(FromF, Lang_CXX11); + ASSERT_TRUE(ToF); + FunctionProtoTypeLoc TL = + ToF->getTypeSourceInfo()->getTypeLoc().castAs(); + EXPECT_EQ(TL.getNumParams(), 1u); + EXPECT_TRUE(TL.getParam(0)); +} + +TEST_P(ImportTypeLoc, Lambda) { + // In this test case, first the CXXRecordDecl of the lambda is imported, then + // the operator(). + Decl *FromTU = getTuDecl( + R"( + auto l1 = [](unsigned lp) { return 1; }; + int f(int p) { + return l1(p); + } + )", + Lang_CXX11, "input0.cc"); + FunctionDecl *FromF = FirstDeclMatcher().match( + FromTU, functionDecl(hasName("f"))); + FunctionDecl *ToF = Import(FromF, Lang_CXX11); + ASSERT_TRUE(ToF); + + TranslationUnitDecl *ToTU = ToAST->getASTContext().getTranslationUnitDecl(); + CXXMethodDecl *ToLambdaMD = FirstDeclMatcher() + .match(ToTU, lambdaExpr()) + ->getCallOperator(); + FunctionProtoTypeLoc TL = ToLambdaMD->getTypeSourceInfo() + ->getTypeLoc() + .castAs(); + EXPECT_EQ(TL.getNumParams(), 1u); + EXPECT_TRUE(TL.getParam(0)); +} + INSTANTIATE_TEST_CASE_P(ParameterizedTests, ASTImporterLookupTableTest, DefaultTestValuesForRunOptions, ); @@ -5903,5 +5950,8 @@ INSTANTIATE_TEST_CASE_P(ParameterizedTests, LLDBLookupTest, DefaultTestValuesForRunOptions, ); +INSTANTIATE_TEST_CASE_P(ParameterizedTests, ImportTypeLoc, + DefaultTestValuesForRunOptions, ); + } // end namespace ast_matchers } // end namespace clang