Skip to content

Commit 0cb2746

Browse files
committed
Keep track of source files created for macro expansions and such.
Introduce a new source file kind to describe source files for macro expansions, and include the macro expression that they expand. This establishes a "parent" relationship Also track every kind of auxiliary source file---whether for macro expansions or other reasons---that is introduced into a module, adding an operation that allows us to find the source file that contains a given source location.
1 parent 60c8b4b commit 0cb2746

14 files changed

+198
-7
lines changed

include/swift/AST/Module.h

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,8 @@ enum class SourceFileKind {
106106
Library, ///< A normal .swift file.
107107
Main, ///< A .swift file that can have top-level code.
108108
SIL, ///< Came from a .sil file.
109-
Interface ///< Came from a .swiftinterface file, representing another module.
109+
Interface, ///< Came from a .swiftinterface file, representing another module.
110+
MacroExpansion, ///< Came from a macro expansion.
110111
};
111112

112113
/// Contains information about where a particular path is used in
@@ -158,6 +159,10 @@ enum class ResilienceStrategy : unsigned {
158159

159160
class OverlayFile;
160161

162+
/// A mapping used to find the source file that contains a particular source
163+
/// location.
164+
class ModuleSourceFileLocationMap;
165+
161166
/// The minimum unit of compilation.
162167
///
163168
/// A module is made up of several file-units, which are all part of the same
@@ -229,6 +234,13 @@ class ModuleDecl
229234

230235
SmallVector<FileUnit *, 2> Files;
231236

237+
/// Mapping used to find the source file associated with a given source
238+
/// location.
239+
ModuleSourceFileLocationMap *sourceFileLocationMap = nullptr;
240+
241+
/// The set of auxiliary source files build as part of this module.
242+
SmallVector<SourceFile *, 2> AuxiliaryFiles;
243+
232244
llvm::SmallDenseMap<Identifier, SmallVector<OverlayFile *, 1>>
233245
declaredCrossImports;
234246

@@ -328,6 +340,13 @@ class ModuleDecl
328340
/// SynthesizedFileUnit instead.
329341
void addFile(FileUnit &newFile);
330342

343+
/// Add an auxiliary source file, introduced as part of the translation.
344+
void addAuxiliaryFile(SourceFile &sourceFile);
345+
346+
/// Produces the source file that contains the given source location, or
347+
/// \c nullptr if the source location isn't in this module.
348+
SourceFile *getSourceFileContainingLocation(SourceLoc loc);
349+
331350
/// Creates a map from \c #filePath strings to corresponding \c #fileID
332351
/// strings, diagnosing any conflicts.
333352
///
@@ -414,6 +433,9 @@ class ModuleDecl
414433
/// present overlays as if they were part of their underlying module.
415434
std::pair<ModuleDecl *, Identifier> getDeclaringModuleAndBystander();
416435

436+
/// Update the source-file location map to make it current.
437+
void updateSourceFileLocationMap();
438+
417439
public:
418440
/// If this is a traditional (non-cross-import) overlay, get its underlying
419441
/// module if one exists.

include/swift/AST/SourceFile.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef SWIFT_AST_SOURCEFILE_H
1414
#define SWIFT_AST_SOURCEFILE_H
1515

16+
#include "swift/AST/ASTNode.h"
1617
#include "swift/AST/FileUnit.h"
1718
#include "swift/AST/Import.h"
1819
#include "swift/AST/SynthesizedFileUnit.h"
@@ -195,6 +196,15 @@ class SourceFile final : public FileUnit {
195196
friend ASTContext;
196197

197198
public:
199+
/// For source files created to hold the source code created by expanding
200+
/// a macro, this is the AST node that describes the macro expansion.
201+
///
202+
/// The source location of this AST node is the place in the source that
203+
/// triggered the creation of the macro expansion whose resulting source
204+
/// code is in this source file. This field is only valid when
205+
/// the \c SourceFileKind is \c MacroExpansion.
206+
const ASTNode macroExpansion;
207+
198208
/// Appends the given declaration to the end of the top-level decls list. Do
199209
/// not add any additional uses of this function.
200210
void addTopLevelDecl(Decl *d) {
@@ -326,7 +336,8 @@ class SourceFile final : public FileUnit {
326336
llvm::StringMap<SourceFilePathInfo> getInfoForUsedFilePaths() const;
327337

328338
SourceFile(ModuleDecl &M, SourceFileKind K, Optional<unsigned> bufferID,
329-
ParsingOptions parsingOpts = {}, bool isPrimary = false);
339+
ParsingOptions parsingOpts = {}, bool isPrimary = false,
340+
ASTNode macroExpansion = ASTNode());
330341

331342
~SourceFile();
332343

@@ -487,6 +498,11 @@ class SourceFile final : public FileUnit {
487498
return BufferID;
488499
}
489500

501+
/// When this source file is enclosed within another source file, for example
502+
/// because it describes a macro expansion, return the source file it was
503+
/// enclosed in.
504+
SourceFile *getEnclosingSourceFile() const;
505+
490506
/// If this buffer corresponds to a file on disk, returns the path.
491507
/// Otherwise, return an empty string.
492508
StringRef getFilename() const;
@@ -545,6 +561,7 @@ class SourceFile final : public FileUnit {
545561
case SourceFileKind::Library:
546562
case SourceFileKind::Interface:
547563
case SourceFileKind::SIL:
564+
case SourceFileKind::MacroExpansion:
548565
return false;
549566
}
550567
llvm_unreachable("bad SourceFileKind");

lib/AST/Module.cpp

Lines changed: 134 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,6 +514,123 @@ void ModuleDecl::addFile(FileUnit &newFile) {
514514
clearLookupCache();
515515
}
516516

517+
void ModuleDecl::addAuxiliaryFile(SourceFile &sourceFile) {
518+
AuxiliaryFiles.push_back(&sourceFile);
519+
}
520+
521+
namespace {
522+
/// Compare the source location ranges for two files, as an ordering to
523+
/// use for fast searches.
524+
struct SourceFileRangeComparison {
525+
SourceManager *sourceMgr;
526+
527+
bool operator()(SourceFile *lhs, SourceFile *rhs) const {
528+
auto lhsRange = sourceMgr->getRangeForBuffer(*lhs->getBufferID());
529+
auto rhsRange = sourceMgr->getRangeForBuffer(*rhs->getBufferID());
530+
531+
std::less<const char *> pointerCompare;
532+
return pointerCompare(
533+
(const char *)lhsRange.getStart().getOpaquePointerValue(),
534+
(const char *)rhsRange.getStart().getOpaquePointerValue());
535+
}
536+
537+
bool operator()(SourceFile *lhs, SourceLoc rhsLoc) const {
538+
auto lhsRange = sourceMgr->getRangeForBuffer(*lhs->getBufferID());
539+
540+
std::less<const char *> pointerCompare;
541+
return pointerCompare(
542+
(const char *)lhsRange.getEnd().getOpaquePointerValue(),
543+
(const char *)rhsLoc.getOpaquePointerValue());
544+
}
545+
546+
bool operator()(SourceLoc lhsLoc, SourceFile *rhs) const {
547+
auto rhsRange = sourceMgr->getRangeForBuffer(*rhs->getBufferID());
548+
549+
std::less<const char *> pointerCompare;
550+
return pointerCompare(
551+
(const char *)lhsLoc.getOpaquePointerValue(),
552+
(const char *)rhsRange.getEnd().getOpaquePointerValue());
553+
}
554+
};
555+
}
556+
557+
class swift::ModuleSourceFileLocationMap {
558+
public:
559+
unsigned numFiles = 0;
560+
unsigned numAuxiliaryFiles = 0;
561+
std::vector<SourceFile *> allSourceFiles;
562+
};
563+
564+
void ModuleDecl::updateSourceFileLocationMap() {
565+
// Allocate a source file location map, if we don't have one already.
566+
if (!sourceFileLocationMap) {
567+
ASTContext &ctx = getASTContext();
568+
sourceFileLocationMap = ctx.Allocate<ModuleSourceFileLocationMap>();
569+
ctx.addCleanup([sourceFileLocationMap=sourceFileLocationMap]() {
570+
sourceFileLocationMap->~ModuleSourceFileLocationMap();
571+
});
572+
}
573+
574+
// If we are up-to-date, there's nothing to do.
575+
if (sourceFileLocationMap->numFiles == getFiles().size() &&
576+
sourceFileLocationMap->numAuxiliaryFiles ==
577+
AuxiliaryFiles.size())
578+
return;
579+
580+
// Rebuild the range structure.
581+
sourceFileLocationMap->allSourceFiles.clear();
582+
583+
// First, add all of the source files with a backing buffer.
584+
for (auto *fileUnit : getFiles()) {
585+
if (auto sourceFile = dyn_cast<SourceFile>(fileUnit)) {
586+
if (sourceFile->getBufferID())
587+
sourceFileLocationMap->allSourceFiles.push_back(sourceFile);
588+
}
589+
}
590+
591+
// Next, add all of the macro expansion files.
592+
for (auto *sourceFile : AuxiliaryFiles)
593+
sourceFileLocationMap->allSourceFiles.push_back(sourceFile);
594+
595+
// Finally, sort them all so we can do a binary search for lookup.
596+
std::sort(sourceFileLocationMap->allSourceFiles.begin(),
597+
sourceFileLocationMap->allSourceFiles.end(),
598+
SourceFileRangeComparison{&getASTContext().SourceMgr});
599+
}
600+
601+
SourceFile *ModuleDecl::getSourceFileContainingLocation(SourceLoc loc) {
602+
if (loc.isInvalid())
603+
return nullptr;
604+
605+
SourceLoc adjustedLoc = loc;
606+
607+
// Check whether this location is in a "replaced" range, in which case
608+
// we want to use the original source file.
609+
auto &sourceMgr = getASTContext().SourceMgr;
610+
for (const auto &pair : sourceMgr.getReplacedRanges()) {
611+
if (sourceMgr.rangeContainsTokenLoc(pair.second, loc)) {
612+
adjustedLoc = pair.first.Start;
613+
break;
614+
}
615+
}
616+
updateSourceFileLocationMap();
617+
618+
auto found = std::lower_bound(sourceFileLocationMap->allSourceFiles.begin(),
619+
sourceFileLocationMap->allSourceFiles.end(),
620+
adjustedLoc,
621+
SourceFileRangeComparison{&sourceMgr});
622+
if (found == sourceFileLocationMap->allSourceFiles.end())
623+
return nullptr;
624+
625+
auto foundSourceFile = *found;
626+
auto foundRange = sourceMgr.getRangeForBuffer(*foundSourceFile->getBufferID());
627+
if (!foundRange.contains(adjustedLoc))
628+
return nullptr;
629+
630+
631+
return foundSourceFile;
632+
}
633+
517634
ArrayRef<SourceFile *>
518635
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
519636
ModuleDecl *mod) const {
@@ -747,6 +864,14 @@ void SourceFile::lookupClassMembers(ImportPath::Access accessPath,
747864
cache.lookupClassMembers(accessPath, consumer);
748865
}
749866

867+
SourceFile *SourceFile::getEnclosingSourceFile() const {
868+
if (Kind != SourceFileKind::MacroExpansion)
869+
return nullptr;
870+
871+
auto sourceLoc = macroExpansion.getStartLoc();
872+
return getParentModule()->getSourceFileContainingLocation(sourceLoc);
873+
}
874+
750875
void ModuleDecl::lookupClassMember(ImportPath::Access accessPath,
751876
DeclName name,
752877
SmallVectorImpl<ValueDecl*> &results) const {
@@ -3075,19 +3200,26 @@ ModuleDecl::computeFileIDMap(bool shouldDiagnose) const {
30753200

30763201
SourceFile::SourceFile(ModuleDecl &M, SourceFileKind K,
30773202
Optional<unsigned> bufferID,
3078-
ParsingOptions parsingOpts, bool isPrimary)
3203+
ParsingOptions parsingOpts, bool isPrimary,
3204+
ASTNode macroExpansion)
30793205
: FileUnit(FileUnitKind::Source, M), BufferID(bufferID ? *bufferID : -1),
3080-
ParsingOpts(parsingOpts), IsPrimary(isPrimary), Kind(K) {
3206+
ParsingOpts(parsingOpts), IsPrimary(isPrimary),
3207+
macroExpansion(macroExpansion), Kind(K) {
30813208
M.getASTContext().addDestructorCleanup(*this);
30823209

30833210
assert(!IsPrimary || M.isMainModule() &&
30843211
"A primary cannot appear outside the main module");
3212+
assert(macroExpansion.isNull() == (K != SourceFileKind::MacroExpansion) &&
3213+
"Macro expansions always need an expansion node");
30853214

30863215
if (isScriptMode()) {
30873216
bool problem = M.registerEntryPointFile(this, SourceLoc(), None);
30883217
assert(!problem && "multiple main files?");
30893218
(void)problem;
30903219
}
3220+
3221+
if (Kind == SourceFileKind::MacroExpansion)
3222+
M.addAuxiliaryFile(*this);
30913223
}
30923224

30933225
SourceFile::ParsingOptions

lib/ClangImporter/ImportDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7227,6 +7227,7 @@ SourceFile &ClangImporter::Implementation::getClangSwiftAttrSourceFile(
72277227
auto sourceFile = new (SwiftContext) SourceFile(
72287228
module, SourceFileKind::Library, None);
72297229
ClangSwiftAttrSourceFiles.insert({&module, sourceFile});
7230+
module.addAuxiliaryFile(*sourceFile);
72307231
return *sourceFile;
72317232
}
72327233

lib/IDETool/CompileInstance.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ getModifiedFunctionDeclList(const SourceFile &SF, SourceManager &tmpSM,
136136
auto tmpBufferID = tmpSM.addNewSourceBuffer(std::move(*tmpBuffer));
137137
SourceFile *tmpSF = new (tmpCtx)
138138
SourceFile(*tmpM, SF.Kind, tmpBufferID, SF.getParsingOptions());
139+
tmpM->addAuxiliaryFile(*tmpSF);
139140

140141
// If the top-level code has been changed, we can't do anything.
141142
if (SF.getInterfaceHash() != tmpSF->getInterfaceHash())

lib/IDETool/CompletionInstance.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ bool CompletionInstance::performCachedOperationIfPossible(
252252
ModuleDecl *tmpM = ModuleDecl::create(Identifier(), *tmpCtx);
253253
SourceFile *tmpSF = new (*tmpCtx)
254254
SourceFile(*tmpM, oldSF->Kind, tmpBufferID, oldSF->getParsingOptions());
255+
tmpM->addAuxiliaryFile(*tmpSF);
255256

256257
// FIXME: Since we don't setup module loaders on the temporary AST context,
257258
// 'canImport()' conditional compilation directive always fails. That causes

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8751,6 +8751,7 @@ parseDeclDeinit(ParseDeclOptions Flags, DeclAttributes &Attributes) {
87518751
break;
87528752
case SourceFileKind::Library:
87538753
case SourceFileKind::Main:
8754+
case SourceFileKind::MacroExpansion:
87548755
if (Tok.is(tok::identifier)) {
87558756
diagnose(Tok, diag::destructor_has_name).fixItRemove(Tok.getLoc());
87568757
consumeToken();

lib/Parse/Parser.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ static LexerMode sourceFileKindToLexerMode(SourceFileKind kind) {
370370
return LexerMode::SIL;
371371
case swift::SourceFileKind::Library:
372372
case swift::SourceFileKind::Main:
373+
case swift::SourceFileKind::MacroExpansion:
373374
return LexerMode::Swift;
374375
}
375376
llvm_unreachable("covered switch");
@@ -1250,6 +1251,7 @@ struct ParserUnit::Implementation {
12501251

12511252
auto *M = ModuleDecl::create(Ctx.getIdentifier(ModuleName), Ctx);
12521253
SF = new (Ctx) SourceFile(*M, SFKind, BufferID, parsingOpts);
1254+
M->addAuxiliaryFile(*SF);
12531255
}
12541256

12551257
~Implementation() {

lib/Sema/CodeSynthesisDistributedActor.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,7 @@ addDistributedActorCodableConformance(
788788

789789
case SourceFileKind::Library:
790790
case SourceFileKind::Main:
791+
case SourceFileKind::MacroExpansion:
791792
case SourceFileKind::SIL:
792793
break;
793794
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ static bool shouldInferAttributeInContext(const DeclContext *dc) {
4545
return false;
4646

4747
case SourceFileKind::Library:
48+
case SourceFileKind::MacroExpansion:
4849
case SourceFileKind::Main:
4950
case SourceFileKind::SIL:
5051
return true;
@@ -4486,6 +4487,7 @@ ProtocolConformance *GetImplicitSendableRequest::evaluate(
44864487
return nullptr;
44874488

44884489
case SourceFileKind::Library:
4490+
case SourceFileKind::MacroExpansion:
44894491
case SourceFileKind::Main:
44904492
case SourceFileKind::SIL:
44914493
break;

0 commit comments

Comments
 (0)