Skip to content

Commit d22f877

Browse files
committed
[CrossTU] Add a function to retrieve original source location.
Summary: A new function will be added to get the original SourceLocation for a SourceLocation that was imported as result of getCrossTUDefinition. The returned SourceLocation is in the context of the (original) SourceManager for the original source file. Additionally the ASTUnit object for that source file is returned. This is needed to get a SourceManager to operate on with the returned source location. The new function works if multiple different source files are loaded with the same CrossTU context. Reviewers: martong, shafik Reviewed By: martong Subscribers: rnkovacs, dkrupp, Szelethus, gamesh411, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D65064 llvm-svn: 366884
1 parent 5a43ba8 commit d22f877

File tree

5 files changed

+116
-18
lines changed

5 files changed

+116
-18
lines changed

clang/include/clang/AST/ASTImporter.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,8 @@ class TypeSourceInfo;
8787
using NonEquivalentDeclSet = llvm::DenseSet<std::pair<Decl *, Decl *>>;
8888
using ImportedCXXBaseSpecifierMap =
8989
llvm::DenseMap<const CXXBaseSpecifier *, CXXBaseSpecifier *>;
90+
using FileIDImportHandlerType =
91+
std::function<void(FileID /*ToID*/, FileID /*FromID*/)>;
9092

9193
// An ImportPath is the list of the AST nodes which we visit during an
9294
// Import call.
@@ -210,6 +212,8 @@ class TypeSourceInfo;
210212
};
211213

212214
private:
215+
FileIDImportHandlerType FileIDImportHandler;
216+
213217
std::shared_ptr<ASTImporterSharedState> SharedState = nullptr;
214218

215219
/// The path which we go through during the import of a given AST node.
@@ -310,6 +314,14 @@ class TypeSourceInfo;
310314

311315
virtual ~ASTImporter();
312316

317+
/// Set a callback function for FileID import handling.
318+
/// The function is invoked when a FileID is imported from the From context.
319+
/// The imported FileID in the To context and the original FileID in the
320+
/// From context is passed to it.
321+
void setFileIDImportHandler(FileIDImportHandlerType H) {
322+
FileIDImportHandler = H;
323+
}
324+
313325
/// Whether the importer will perform a minimal import, creating
314326
/// to-be-completed forward declarations when possible.
315327
bool isMinimalImport() const { return Minimal; }

clang/include/clang/CrossTU/CrossTranslationUnit.h

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -153,18 +153,34 @@ class CrossTranslationUnitContext {
153153
/// was passed to the constructor.
154154
///
155155
/// \return Returns the resulting definition or an error.
156-
llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD);
157-
llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD);
156+
llvm::Expected<const FunctionDecl *> importDefinition(const FunctionDecl *FD,
157+
ASTUnit *Unit);
158+
llvm::Expected<const VarDecl *> importDefinition(const VarDecl *VD,
159+
ASTUnit *Unit);
158160

159161
/// Get a name to identify a named decl.
160162
static std::string getLookupName(const NamedDecl *ND);
161163

162164
/// Emit diagnostics for the user for potential configuration errors.
163165
void emitCrossTUDiagnostics(const IndexError &IE);
164166

167+
/// Determine the original source location in the original TU for an
168+
/// imported source location.
169+
/// \p ToLoc Source location in the imported-to AST.
170+
/// \return Source location in the imported-from AST and the corresponding
171+
/// ASTUnit object (the AST was loaded from a file using an internal ASTUnit
172+
/// object that is returned here).
173+
/// If any error happens (ToLoc is a non-imported source location) empty is
174+
/// returned.
175+
llvm::Optional<std::pair<SourceLocation /*FromLoc*/, ASTUnit *>>
176+
getImportedFromSourceLocation(const clang::SourceLocation &ToLoc) const;
177+
165178
private:
179+
using ImportedFileIDMap =
180+
llvm::DenseMap<FileID, std::pair<FileID, ASTUnit *>>;
181+
166182
void lazyInitImporterSharedSt(TranslationUnitDecl *ToTU);
167-
ASTImporter &getOrCreateASTImporter(ASTContext &From);
183+
ASTImporter &getOrCreateASTImporter(ASTUnit *Unit);
168184
template <typename T>
169185
llvm::Expected<const T *> getCrossTUDefinitionImpl(const T *D,
170186
StringRef CrossTUDir,
@@ -174,7 +190,7 @@ class CrossTranslationUnitContext {
174190
const T *findDefInDeclContext(const DeclContext *DC,
175191
StringRef LookupName);
176192
template <typename T>
177-
llvm::Expected<const T *> importDefinitionImpl(const T *D);
193+
llvm::Expected<const T *> importDefinitionImpl(const T *D, ASTUnit *Unit);
178194

179195
llvm::StringMap<std::unique_ptr<clang::ASTUnit>> FileASTUnitMap;
180196
llvm::StringMap<clang::ASTUnit *> NameASTUnitMap;
@@ -184,6 +200,15 @@ class CrossTranslationUnitContext {
184200
CompilerInstance &CI;
185201
ASTContext &Context;
186202
std::shared_ptr<ASTImporterSharedState> ImporterSharedSt;
203+
/// Map of imported FileID's (in "To" context) to FileID in "From" context
204+
/// and the ASTUnit for the From context.
205+
/// This map is used by getImportedFromSourceLocation to lookup a FileID and
206+
/// its Preprocessor when knowing only the FileID in the 'To' context. The
207+
/// FileID could be imported by any of multiple 'From' ASTImporter objects.
208+
/// we do not want to loop over all ASTImporter's to find the one that
209+
/// imported the FileID.
210+
ImportedFileIDMap ImportedFileIDs;
211+
187212
/// \p CTULoadTreshold should serve as an upper limit to the number of TUs
188213
/// imported in order to reduce the memory footprint of CTU analysis.
189214
const unsigned CTULoadThreshold;

clang/lib/AST/ASTImporter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8421,6 +8421,10 @@ Expected<FileID> ASTImporter::Import(FileID FromID, bool IsBuiltin) {
84218421
assert(ToID.isValid() && "Unexpected invalid fileID was created.");
84228422

84238423
ImportedFileIDs[FromID] = ToID;
8424+
8425+
if (FileIDImportHandler)
8426+
FileIDImportHandler(ToID, FromID);
8427+
84248428
return ToID;
84258429
}
84268430

clang/lib/CrossTU/CrossTranslationUnit.cpp

Lines changed: 38 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -295,7 +295,7 @@ llvm::Expected<const T *> CrossTranslationUnitContext::getCrossTUDefinitionImpl(
295295

296296
TranslationUnitDecl *TU = Unit->getASTContext().getTranslationUnitDecl();
297297
if (const T *ResultDecl = findDefInDeclContext<T>(TU, LookupName))
298-
return importDefinition(ResultDecl);
298+
return importDefinition(ResultDecl, Unit);
299299
return llvm::make_error<IndexError>(index_error_code::failed_import);
300300
}
301301

@@ -411,10 +411,13 @@ llvm::Expected<ASTUnit *> CrossTranslationUnitContext::loadExternalAST(
411411

412412
template <typename T>
413413
llvm::Expected<const T *>
414-
CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
414+
CrossTranslationUnitContext::importDefinitionImpl(const T *D, ASTUnit *Unit) {
415415
assert(hasBodyOrInit(D) && "Decls to be imported should have body or init.");
416416

417-
ASTImporter &Importer = getOrCreateASTImporter(D->getASTContext());
417+
assert(&D->getASTContext() == &Unit->getASTContext() &&
418+
"ASTContext of Decl and the unit should match.");
419+
ASTImporter &Importer = getOrCreateASTImporter(Unit);
420+
418421
auto ToDeclOrError = Importer.Import(D);
419422
if (!ToDeclOrError) {
420423
handleAllErrors(ToDeclOrError.takeError(),
@@ -441,13 +444,15 @@ CrossTranslationUnitContext::importDefinitionImpl(const T *D) {
441444
}
442445

443446
llvm::Expected<const FunctionDecl *>
444-
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD) {
445-
return importDefinitionImpl(FD);
447+
CrossTranslationUnitContext::importDefinition(const FunctionDecl *FD,
448+
ASTUnit *Unit) {
449+
return importDefinitionImpl(FD, Unit);
446450
}
447451

448452
llvm::Expected<const VarDecl *>
449-
CrossTranslationUnitContext::importDefinition(const VarDecl *VD) {
450-
return importDefinitionImpl(VD);
453+
CrossTranslationUnitContext::importDefinition(const VarDecl *VD,
454+
ASTUnit *Unit) {
455+
return importDefinitionImpl(VD, Unit);
451456
}
452457

453458
void CrossTranslationUnitContext::lazyInitImporterSharedSt(
@@ -457,17 +462,42 @@ void CrossTranslationUnitContext::lazyInitImporterSharedSt(
457462
}
458463

459464
ASTImporter &
460-
CrossTranslationUnitContext::getOrCreateASTImporter(ASTContext &From) {
465+
CrossTranslationUnitContext::getOrCreateASTImporter(ASTUnit *Unit) {
466+
ASTContext &From = Unit->getASTContext();
467+
461468
auto I = ASTUnitImporterMap.find(From.getTranslationUnitDecl());
462469
if (I != ASTUnitImporterMap.end())
463470
return *I->second;
464471
lazyInitImporterSharedSt(Context.getTranslationUnitDecl());
465472
ASTImporter *NewImporter = new ASTImporter(
466473
Context, Context.getSourceManager().getFileManager(), From,
467474
From.getSourceManager().getFileManager(), false, ImporterSharedSt);
475+
NewImporter->setFileIDImportHandler([this, Unit](FileID ToID, FileID FromID) {
476+
assert(ImportedFileIDs.find(ToID) == ImportedFileIDs.end() &&
477+
"FileID already imported, should not happen.");
478+
ImportedFileIDs[ToID] = std::make_pair(FromID, Unit);
479+
});
468480
ASTUnitImporterMap[From.getTranslationUnitDecl()].reset(NewImporter);
469481
return *NewImporter;
470482
}
471483

484+
llvm::Optional<std::pair<SourceLocation, ASTUnit *>>
485+
CrossTranslationUnitContext::getImportedFromSourceLocation(
486+
const clang::SourceLocation &ToLoc) const {
487+
const SourceManager &SM = Context.getSourceManager();
488+
auto DecToLoc = SM.getDecomposedLoc(ToLoc);
489+
490+
auto I = ImportedFileIDs.find(DecToLoc.first);
491+
if (I == ImportedFileIDs.end())
492+
return {};
493+
494+
FileID FromID = I->second.first;
495+
clang::ASTUnit *Unit = I->second.second;
496+
SourceLocation FromLoc =
497+
Unit->getSourceManager().getComposedLoc(FromID, DecToLoc.second);
498+
499+
return std::make_pair(FromLoc, Unit);
500+
}
501+
472502
} // namespace cross_tu
473503
} // namespace clang

clang/unittests/CrossTU/CrossTranslationUnitTest.cpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,18 @@ class CTUASTConsumer : public clang::ASTConsumer {
2828
: CTU(CI), Success(Success) {}
2929

3030
void HandleTranslationUnit(ASTContext &Ctx) {
31+
auto FindFInTU = [](const TranslationUnitDecl *TU) {
32+
const FunctionDecl *FD = nullptr;
33+
for (const Decl *D : TU->decls()) {
34+
FD = dyn_cast<FunctionDecl>(D);
35+
if (FD && FD->getName() == "f")
36+
break;
37+
}
38+
return FD;
39+
};
40+
3141
const TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl();
32-
const FunctionDecl *FD = nullptr;
33-
for (const Decl *D : TU->decls()) {
34-
FD = dyn_cast<FunctionDecl>(D);
35-
if (FD && FD->getName() == "f")
36-
break;
37-
}
42+
const FunctionDecl *FD = FindFInTU(TU);
3843
assert(FD && FD->getName() == "f");
3944
bool OrigFDHasBody = FD->hasBody();
4045

@@ -78,6 +83,28 @@ class CTUASTConsumer : public clang::ASTConsumer {
7883
if (NewFDorError) {
7984
const FunctionDecl *NewFD = *NewFDorError;
8085
*Success = NewFD && NewFD->hasBody() && !OrigFDHasBody;
86+
87+
if (NewFD) {
88+
// Check GetImportedFromSourceLocation.
89+
llvm::Optional<std::pair<SourceLocation, ASTUnit *>> SLocResult =
90+
CTU.getImportedFromSourceLocation(NewFD->getLocation());
91+
EXPECT_TRUE(SLocResult);
92+
if (SLocResult) {
93+
SourceLocation OrigSLoc = (*SLocResult).first;
94+
ASTUnit *OrigUnit = (*SLocResult).second;
95+
// OrigUnit is created internally by CTU (is not the
96+
// ASTWithDefinition).
97+
TranslationUnitDecl *OrigTU =
98+
OrigUnit->getASTContext().getTranslationUnitDecl();
99+
const FunctionDecl *FDWithDefinition = FindFInTU(OrigTU);
100+
EXPECT_TRUE(FDWithDefinition);
101+
if (FDWithDefinition) {
102+
EXPECT_EQ(FDWithDefinition->getName(), "f");
103+
EXPECT_TRUE(FDWithDefinition->isThisDeclarationADefinition());
104+
EXPECT_EQ(OrigSLoc, FDWithDefinition->getLocation());
105+
}
106+
}
107+
}
81108
}
82109
}
83110

0 commit comments

Comments
 (0)