Index: include/clang/AST/ASTImporter.h =================================================================== --- include/clang/AST/ASTImporter.h +++ include/clang/AST/ASTImporter.h @@ -34,6 +34,7 @@ class ASTContext; class ASTImporterSharedState; +class ASTUnit; class Attr; class CXXBaseSpecifier; class CXXCtorInitializer; @@ -229,6 +230,9 @@ /// The file managers we're importing to and from. FileManager &ToFileManager, &FromFileManager; + /// The ASTUnit that this importer belongs to, if any. + ASTUnit *Unit; + /// Whether to perform a minimal import. bool Minimal; @@ -287,7 +291,6 @@ virtual bool returnWithErrorInTest() { return false; }; public: - /// \param ToContext The context we'll be importing into. /// /// \param ToFileManager The file manager we'll be importing into. @@ -303,10 +306,15 @@ /// \param SharedState The importer specific lookup table which may be /// shared amongst several ASTImporter objects. /// If not set then the original C/C++ lookup is used. + /// + /// \param Unit Pointer to an ASTUnit that contains this importer, if any. + /// A mapping of imported FileID's to ASTUnit is stored in the shared state, + /// if both are set. ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, - std::shared_ptr SharedState = nullptr); + std::shared_ptr SharedState = nullptr, + ASTUnit *Unit = nullptr); virtual ~ASTImporter(); Index: include/clang/AST/ASTImporterSharedState.h =================================================================== --- include/clang/AST/ASTImporterSharedState.h +++ include/clang/AST/ASTImporterSharedState.h @@ -17,18 +17,24 @@ #include "clang/AST/ASTImporterLookupTable.h" #include "clang/AST/Decl.h" +#include "clang/Basic/SourceLocation.h" #include "llvm/ADT/DenseMap.h" // FIXME We need this because of ImportError. #include "clang/AST/ASTImporter.h" namespace clang { +class ASTUnit; class TranslationUnitDecl; /// Importer specific state, which may be shared amongst several ASTImporter /// objects. class ASTImporterSharedState { +public: + using ImportedFileIDMap = + llvm::DenseMap>; +private: /// Pointer to the import specific lookup table. std::unique_ptr LookupTable; @@ -43,6 +49,16 @@ // FIXME put ImportedFromDecls here! // And from that point we can better encapsulate the lookup table. + /// Map of imported FileID's (in "To" context) to FileID in "From" context + /// and the ASTUnit that contains the preprocessor and source manager for the + /// "From" FileID. This map is used to lookup a FileID and its SourceManager + /// when knowing only the FileID in the 'To' context. The FileID could be + /// imported by any of multiple ASTImporter objects. The map is used because + /// we do not want to loop over all ASTImporter's to find the one that + /// imported the FileID. (The ASTUnit is usable to get the SourceManager and + /// additional data.) + ImportedFileIDMap ImportedFileIDs; + public: ASTImporterSharedState() = default; @@ -75,6 +91,12 @@ void setImportDeclError(Decl *To, ImportError Error) { ImportErrors[To] = Error; } + + ImportedFileIDMap &getImportedFileIDs() { return ImportedFileIDs; } + + const ImportedFileIDMap &getImportedFileIDs() const { + return ImportedFileIDs; + } }; } // namespace clang Index: include/clang/CrossTU/CrossTranslationUnit.h =================================================================== --- include/clang/CrossTU/CrossTranslationUnit.h +++ include/clang/CrossTU/CrossTranslationUnit.h @@ -153,8 +153,10 @@ /// was passed to the constructor. /// /// \return Returns the resulting definition or an error. - llvm::Expected importDefinition(const FunctionDecl *FD); - llvm::Expected importDefinition(const VarDecl *VD); + llvm::Expected importDefinition(const FunctionDecl *FD, + ASTUnit *Unit); + llvm::Expected importDefinition(const VarDecl *VD, + ASTUnit *Unit); /// Get a name to identify a named decl. static std::string getLookupName(const NamedDecl *ND); @@ -162,9 +164,19 @@ /// Emit diagnostics for the user for potential configuration errors. void emitCrossTUDiagnostics(const IndexError &IE); + /// Determine the original source location in the original TU for an + /// imported source location. + /// \p ToLoc Source location in the imported-to AST. + /// \return Source location in the imported-from AST and the corresponding + /// ASTUnit. + /// If any error happens (ToLoc is a non-imported source location) empty is + /// returned. + llvm::Optional> + getImportedFromSourceLocation(const clang::SourceLocation &ToLoc) const; + private: void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU); - ASTImporter &getOrCreateASTImporter(ASTContext &From); + ASTImporter &getOrCreateASTImporter(ASTUnit *Unit); template llvm::Expected getCrossTUDefinitionImpl(const T *D, StringRef CrossTUDir, @@ -174,7 +186,7 @@ const T *findDefInDeclContext(const DeclContext *DC, StringRef LookupName); template - llvm::Expected importDefinitionImpl(const T *D); + llvm::Expected importDefinitionImpl(const T *D, ASTUnit *Unit); llvm::StringMap> FileASTUnitMap; llvm::StringMap NameASTUnitMap; Index: lib/AST/ASTImporter.cpp =================================================================== --- lib/AST/ASTImporter.cpp +++ lib/AST/ASTImporter.cpp @@ -7704,10 +7704,11 @@ ASTImporter::ASTImporter(ASTContext &ToContext, FileManager &ToFileManager, ASTContext &FromContext, FileManager &FromFileManager, bool MinimalImport, - std::shared_ptr SharedState) + std::shared_ptr SharedState, + ASTUnit *Unit) : SharedState(SharedState), ToContext(ToContext), FromContext(FromContext), ToFileManager(ToFileManager), FromFileManager(FromFileManager), - Minimal(MinimalImport) { + Unit(Unit), Minimal(MinimalImport) { // Create a default state without the lookup table: LLDB case. if (!SharedState) { @@ -8400,6 +8401,13 @@ assert(ToID.isValid() && "Unexpected invalid fileID was created."); ImportedFileIDs[FromID] = ToID; + if (Unit) { + assert(SharedState->getImportedFileIDs().find(ToID) == + SharedState->getImportedFileIDs().end() && + "FileID already imported!"); + SharedState->getImportedFileIDs()[ToID] = std::make_pair(FromID, Unit); + } + return ToID; } Index: lib/CrossTU/CrossTranslationUnit.cpp =================================================================== --- lib/CrossTU/CrossTranslationUnit.cpp +++ lib/CrossTU/CrossTranslationUnit.cpp @@ -295,7 +295,7 @@ TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl(); if (const T *ResultDecl = findDefInDeclContext(TU, LookupName)) - return importDefinition(ResultDecl); + return importDefinition(ResultDecl, Unit); return llvm::make_error(index_error_code::failed_import); } @@ -411,10 +411,13 @@ template llvm::Expected -CrossTranslationUnitContext::importDefinitionImpl(const T *D) { +CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) { assert(hasBodyOrInit(D) && "Decls to be imported should have body or init."); - ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext()); + assert(&D->getASTContext() == &Unit->getASTContext() && + "ASTContext of Decl and the unit should match."); + ASTImporter &Importer = getOrCreateASTImporter(Unit); + auto ToDeclOrError = Importer.Import(D); if (!ToDeclOrError) { handleAllErrors(ToDeclOrError.takeError(), @@ -441,13 +444,15 @@ } llvm::Expected -CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) { - return importDefinitionImpl(FD); +CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD, + ASTUnit *Unit) { + return importDefinitionImpl(FD, Unit); } llvm::Expected -CrossTranslationUnitContext::importDefinition(const VarDecl *VD) { - return importDefinitionImpl(VD); +CrossTranslationUnitContext::importDefinition(const VarDecl *VD, + ASTUnit *Unit) { + return importDefinitionImpl(VD, Unit); } void CrossTranslationUnitContext::lazyInitImporterSharedSt( @@ -457,17 +462,40 @@ } ASTImporter & -CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) { +CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) { + ASTContext &From = Unit->getASTContext(); + auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl()); if (I != ASTUnitImporterMap.end()) return *I->second; lazyInitImporterSharedSt(Context.getTranslationUnitDecl()); ASTImporter *NewImporter = new ASTImporter( Context, Context.getSourceManager().getFileManager(), From, - From.getSourceManager().getFileManager(), false, ImporterSharedSt); + From.getSourceManager().getFileManager(), false, ImporterSharedSt, Unit); ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter); return *NewImporter; } +llvm::Optional> +CrossTranslationUnitContext::getImportedFromSourceLocation( + const clang::SourceLocation &ToLoc) const { + if (!ImporterSharedSt) + return {}; + + const SourceManager &SM = Context.getSourceManager(); + auto DecToLoc = SM.getDecomposedLoc(ToLoc); + + auto I = ImporterSharedSt->getImportedFileIDs().find(DecToLoc.first); + if (I == ImporterSharedSt->getImportedFileIDs().end()) + return {}; + + FileID FromID = I->second.first; + clang::ASTUnit *Unit = I->second.second; + SourceLocation FromLoc = + Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second); + + return std::make_pair(FromLoc, Unit); +} + } // namespace cross_tu } // namespace clang Index: unittests/CrossTU/CrossTranslationUnitTest.cpp =================================================================== --- unittests/CrossTU/CrossTranslationUnitTest.cpp +++ unittests/CrossTU/CrossTranslationUnitTest.cpp @@ -28,13 +28,18 @@ : CTU(CI), Success(Success) {} void HandleTranslationUnit(ASTContext &Ctx) { + auto FindFInTU = [](const TranslationUnitDecl *TU) { + const FunctionDecl *FD = nullptr; + for (const Decl *D : TU->decls()) { + FD = dyn_cast(D); + if (FD && FD->getName() == "f") + break; + } + return FD; + }; + const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); - const FunctionDecl *FD = nullptr; - for (const Decl *D : TU->decls()) { - FD = dyn_cast(D); - if (FD && FD->getName() == "f") - break; - } + const FunctionDecl *FD = FindFInTU(TU); assert(FD && FD->getName() == "f"); bool OrigFDHasBody = FD->hasBody(); @@ -78,6 +83,28 @@ if (NewFDorError) { const FunctionDecl *NewFD = *NewFDorError; *Success = NewFD && NewFD->hasBody() && !OrigFDHasBody; + + if (NewFD) { + // Check GetImportedFromSourceLocation. + llvm::Optional> SLocResult = + CTU.getImportedFromSourceLocation(NewFD->getLocation()); + EXPECT_TRUE(SLocResult); + if (SLocResult) { + SourceLocation OrigSLoc = (*SLocResult).first; + ASTUnit *OrigUnit = (*SLocResult).second; + // OrigUnit is created internally by CTU (is not the + // ASTWithDefinition). + TranslationUnitDecl *OrigTU = + OrigUnit->getASTContext().getTranslationUnitDecl(); + const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU); + EXPECT_TRUE(FDWithDefinition); + if (FDWithDefinition) { + EXPECT_EQ(FDWithDefinition->getName(), "f"); + EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition()); + EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation()); + } + } + } } }