Skip to content

Commit 33727d7

Browse files
authored
Merge pull request #64737 from bnbarham/skip-generated-buffers
[SourceKit] Return the original location for decls within generated code
2 parents 9a55a9d + b9810fb commit 33727d7

File tree

10 files changed

+303
-61
lines changed

10 files changed

+303
-61
lines changed

include/swift/AST/DiagnosticsRefactoring.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ ERROR(decl_no_accessibility, none, "cannot rename as accessibility could not be
4646

4747
ERROR(decl_from_clang, none, "cannot rename a Clang symbol from its Swift reference", ())
4848

49+
ERROR(decl_in_macro, none, "cannot rename a symbol defined in a macro", ())
50+
4951
ERROR(value_decl_referenced_out_of_range, none, "value decl '%0' is referenced out of range", (DeclName))
5052

5153
ERROR(multi_entry_range, none, "selected range has more than one entry point", ())

include/swift/AST/Module.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -410,6 +410,11 @@ class ModuleDecl
410410
/// the given location isn't in this module.
411411
bool isInGeneratedBuffer(SourceLoc loc);
412412

413+
// Retrieve the buffer ID and source location of the outermost location that
414+
// caused the generation of the buffer containing \p loc. \p loc and its
415+
// buffer if it isn't in a generated buffer or has no original location.
416+
std::pair<unsigned, SourceLoc> getOriginalLocation(SourceLoc loc) const;
417+
413418
/// Creates a map from \c #filePath strings to corresponding \c #fileID
414419
/// strings, diagnosing any conflicts.
415420
///

include/swift/Refactoring/Refactoring.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ enum class RefactorAvailableKind {
7979
Unavailable_has_no_name,
8080
Unavailable_has_no_accessibility,
8181
Unavailable_decl_from_clang,
82+
Unavailable_decl_in_macro,
8283
};
8384

8485
struct RefactorAvailabilityInfo {

lib/AST/Module.cpp

Lines changed: 70 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -784,6 +784,49 @@ bool ModuleDecl::isInGeneratedBuffer(SourceLoc loc) {
784784
return file->Kind == SourceFileKind::MacroExpansion;
785785
}
786786

787+
std::pair<unsigned, SourceLoc>
788+
ModuleDecl::getOriginalLocation(SourceLoc loc) const {
789+
assert(loc.isValid());
790+
791+
SourceManager &SM = getASTContext().SourceMgr;
792+
unsigned bufferID = SM.findBufferContainingLoc(loc);
793+
794+
SourceLoc startLoc = loc;
795+
unsigned startBufferID = bufferID;
796+
while (Optional<GeneratedSourceInfo> info =
797+
SM.getGeneratedSourceInfo(bufferID)) {
798+
switch (info->kind) {
799+
case GeneratedSourceInfo::ExpressionMacroExpansion:
800+
case GeneratedSourceInfo::FreestandingDeclMacroExpansion:
801+
case GeneratedSourceInfo::AccessorMacroExpansion:
802+
case GeneratedSourceInfo::MemberAttributeMacroExpansion:
803+
case GeneratedSourceInfo::MemberMacroExpansion:
804+
case GeneratedSourceInfo::PeerMacroExpansion:
805+
case GeneratedSourceInfo::ConformanceMacroExpansion: {
806+
// Location was within a macro expansion, return the expansion site, not
807+
// the insertion location.
808+
if (info->attachedMacroCustomAttr) {
809+
loc = info->attachedMacroCustomAttr->getLocation();
810+
} else {
811+
ASTNode expansionNode = ASTNode::getFromOpaqueValue(info->astNode);
812+
loc = expansionNode.getStartLoc();
813+
}
814+
bufferID = SM.findBufferContainingLoc(loc);
815+
break;
816+
}
817+
case GeneratedSourceInfo::ReplacedFunctionBody:
818+
// There's not really any "original" location for locations within
819+
// replaced function bodies. The body is actually different code to the
820+
// original file.
821+
case GeneratedSourceInfo::PrettyPrinted:
822+
// No original location, return the original buffer/location
823+
return {startBufferID, startLoc};
824+
}
825+
}
826+
827+
return {bufferID, loc};
828+
}
829+
787830
ArrayRef<SourceFile *>
788831
PrimarySourceFilesRequest::evaluate(Evaluator &evaluator,
789832
ModuleDecl *mod) const {
@@ -1321,14 +1364,24 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
13211364
return None;
13221365
}
13231366

1324-
SourceLoc Loc = D->getLoc(/*SerializedOK=*/false);
1325-
if (Loc.isInvalid())
1367+
SourceLoc MainLoc = D->getLoc(/*SerializedOK=*/false);
1368+
if (MainLoc.isInvalid())
13261369
return None;
13271370

1371+
// TODO: Rather than grabbing the location of the macro expansion, we should
1372+
// instead add the generated buffer tree - that would need to include source
1373+
// if we want to be able to retrieve documentation within generated buffers.
13281374
SourceManager &SM = getASTContext().SourceMgr;
1329-
auto BufferID = SM.findBufferContainingLoc(Loc);
1375+
bool InGeneratedBuffer =
1376+
!SM.rangeContainsTokenLoc(SM.getRangeForBuffer(BufferID), MainLoc);
1377+
if (InGeneratedBuffer) {
1378+
int UnderlyingBufferID;
1379+
std::tie(UnderlyingBufferID, MainLoc) =
1380+
D->getModuleContext()->getOriginalLocation(MainLoc);
1381+
if (BufferID != UnderlyingBufferID)
1382+
return None;
1383+
}
13301384

1331-
ExternalSourceLocs::RawLocs Result;
13321385
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {
13331386
if (!Loc.isValid())
13341387
return;
@@ -1347,15 +1400,20 @@ SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
13471400
RawLoc.Directive.Name = StringRef(VF->Name);
13481401
};
13491402

1403+
ExternalSourceLocs::RawLocs Result;
1404+
13501405
Result.SourceFilePath = SM.getIdentifierForBuffer(BufferID);
1351-
for (const auto &SRC : D->getRawComment(/*SerializedOK=*/false).Comments) {
1352-
Result.DocRanges.emplace_back(ExternalSourceLocs::RawLoc(),
1353-
SRC.Range.getByteLength());
1354-
setLoc(Result.DocRanges.back().first, SRC.Range.getStart());
1355-
}
1356-
setLoc(Result.Loc, D->getLoc(/*SerializedOK=*/false));
1357-
setLoc(Result.StartLoc, D->getStartLoc());
1358-
setLoc(Result.EndLoc, D->getEndLoc());
1406+
setLoc(Result.Loc, MainLoc);
1407+
if (!InGeneratedBuffer) {
1408+
for (const auto &SRC : D->getRawComment(/*SerializedOK=*/false).Comments) {
1409+
Result.DocRanges.emplace_back(ExternalSourceLocs::RawLoc(),
1410+
SRC.Range.getByteLength());
1411+
setLoc(Result.DocRanges.back().first, SRC.Range.getStart());
1412+
}
1413+
setLoc(Result.StartLoc, D->getStartLoc());
1414+
setLoc(Result.EndLoc, D->getEndLoc());
1415+
}
1416+
13591417
return Result;
13601418
}
13611419

lib/Index/Index.cpp

Lines changed: 80 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -416,12 +416,19 @@ class ContainerTracker {
416416
}
417417
};
418418

419+
struct MappedLoc {
420+
unsigned Line;
421+
unsigned Column;
422+
bool IsGenerated;
423+
};
424+
419425
class IndexSwiftASTWalker : public SourceEntityWalker {
420426
IndexDataConsumer &IdxConsumer;
421427
SourceManager &SrcMgr;
422428
unsigned BufferID;
423429
bool enableWarnings;
424430

431+
ModuleDecl *CurrentModule = nullptr;
425432
bool IsModuleFile = false;
426433
bool isSystemModule = false;
427434

@@ -584,7 +591,7 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
584591
assert(Cancelled || Containers.empty());
585592
}
586593

587-
/// Walk both the arguments and expansion of the macro, so we index both.Only walk the arguments of a macro, to represent the source as written.
594+
/// Walk both the arguments and expansion of the macro, so we index both.
588595
MacroWalking getMacroWalkingBehavior() const override {
589596
return MacroWalking::ArgumentsAndExpansion;
590597
}
@@ -877,14 +884,17 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
877884
}
878885

879886
bool visitModuleReference(ModuleEntity Mod, CharSourceRange Range) override {
880-
SourceLoc Loc = Range.getStart();
881-
882-
if (Loc.isInvalid())
887+
auto MappedLoc = getMappedLocation(Range.getStart());
888+
if (!MappedLoc)
883889
return true;
884890

885891
IndexSymbol Info;
886-
std::tie(Info.line, Info.column) = getLineCol(Loc);
892+
Info.line = MappedLoc->Line;
893+
Info.column = MappedLoc->Column;
887894
Info.roles |= (unsigned)SymbolRole::Reference;
895+
if (MappedLoc->IsGenerated) {
896+
Info.roles |= (unsigned)SymbolRole::Implicit;
897+
}
888898
Info.symInfo = getSymbolInfoForModule(Mod);
889899
getModuleNameAndUSR(Mod, Info.name, Info.USR);
890900
addContainedByRelationIfContained(Info);
@@ -959,11 +969,11 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
959969

960970
bool reportPseudoGetterDecl(VarDecl *D) {
961971
return reportPseudoAccessor(D, AccessorKind::Get, /*IsRef=*/false,
962-
D->getLoc());
972+
D->getLoc(/*SerializedOK=*/false));
963973
}
964974
bool reportPseudoSetterDecl(VarDecl *D) {
965975
return reportPseudoAccessor(D, AccessorKind::Set, /*IsRef=*/false,
966-
D->getLoc());
976+
D->getLoc(/*SerializedOK=*/false));
967977
}
968978
bool reportPseudoAccessor(AbstractStorageDecl *D, AccessorKind AccKind,
969979
bool IsRef, SourceLoc Loc);
@@ -994,10 +1004,31 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
9941004

9951005
bool indexComment(const Decl *D);
9961006

997-
std::pair<unsigned, unsigned> getLineCol(SourceLoc Loc) {
998-
if (Loc.isInvalid())
999-
return std::make_pair(0, 0);
1000-
return SrcMgr.getLineAndColumnInBuffer(Loc, BufferID);
1007+
// Return the line and column of \p loc, as well as whether it was from a
1008+
// generated buffer or not. 0:0 if indexing a module and \p loc is invalid.
1009+
// \c None if \p loc is otherwise invalid or its original location isn't
1010+
// contained within the current buffer.
1011+
Optional<MappedLoc> getMappedLocation(SourceLoc loc) {
1012+
if (loc.isInvalid()) {
1013+
if (IsModuleFile)
1014+
return {{0, 0, false}};
1015+
return None;
1016+
}
1017+
1018+
bool inGeneratedBuffer =
1019+
!SrcMgr.rangeContainsTokenLoc(SrcMgr.getRangeForBuffer(BufferID), loc);
1020+
1021+
auto bufferID = BufferID;
1022+
if (inGeneratedBuffer) {
1023+
std::tie(bufferID, loc) = CurrentModule->getOriginalLocation(loc);
1024+
if (BufferID != bufferID) {
1025+
assert(false && "Location is not within file being indexed");
1026+
return None;
1027+
}
1028+
}
1029+
1030+
auto [line, col] = SrcMgr.getLineAndColumnInBuffer(loc, bufferID);
1031+
return {{line, col, inGeneratedBuffer}};
10011032
}
10021033

10031034
bool shouldIndex(ValueDecl *D, bool IsRef) const {
@@ -1070,6 +1101,7 @@ class IndexSwiftASTWalker : public SourceEntityWalker {
10701101
} // anonymous namespace
10711102

10721103
void IndexSwiftASTWalker::visitDeclContext(DeclContext *Context) {
1104+
CurrentModule = Context->getParentModule();
10731105
IsModuleFile = false;
10741106
isSystemModule = Context->getParentModule()->isNonUserModule();
10751107
auto accessor = dyn_cast<AccessorDecl>(Context);
@@ -1081,6 +1113,8 @@ void IndexSwiftASTWalker::visitDeclContext(DeclContext *Context) {
10811113
}
10821114

10831115
void IndexSwiftASTWalker::visitModule(ModuleDecl &Mod) {
1116+
CurrentModule = &Mod;
1117+
10841118
SourceFile *SrcFile = nullptr;
10851119
for (auto File : Mod.getFiles()) {
10861120
if (auto SF = dyn_cast<SourceFile>(File)) {
@@ -1662,10 +1696,8 @@ bool IndexSwiftASTWalker::initIndexSymbol(ValueDecl *D, SourceLoc Loc,
16621696
bool IsRef, IndexSymbol &Info) {
16631697
assert(D);
16641698

1665-
if (Loc.isInvalid() && !IsModuleFile)
1666-
return true;
1667-
1668-
if (Loc.isValid() && SrcMgr.findBufferContainingLoc(Loc) != BufferID)
1699+
auto MappedLoc = getMappedLocation(Loc);
1700+
if (!MappedLoc)
16691701
return true;
16701702

16711703
if (auto *VD = dyn_cast<VarDecl>(D)) {
@@ -1674,15 +1706,17 @@ bool IndexSwiftASTWalker::initIndexSymbol(ValueDecl *D, SourceLoc Loc,
16741706
}
16751707

16761708
Info.decl = D;
1709+
Info.line = MappedLoc->Line;
1710+
Info.column = MappedLoc->Column;
16771711
Info.symInfo = getSymbolInfoForDecl(D);
1712+
16781713
if (Info.symInfo.Kind == SymbolKind::Unknown)
16791714
return true;
16801715

16811716
// Cannot be extension, which is not a ValueDecl.
16821717

16831718
if (getNameAndUSR(D, /*ExtD=*/nullptr, Info.name, Info.USR))
16841719
return true;
1685-
std::tie(Info.line, Info.column) = getLineCol(Loc);
16861720

16871721
if (IsRef) {
16881722
Info.roles |= (unsigned)SymbolRole::Reference;
@@ -1695,23 +1729,37 @@ bool IndexSwiftASTWalker::initIndexSymbol(ValueDecl *D, SourceLoc Loc,
16951729
Info.group = Group.value();
16961730
}
16971731

1732+
if (MappedLoc->IsGenerated) {
1733+
Info.roles |= (unsigned)SymbolRole::Implicit;
1734+
}
1735+
16981736
return false;
16991737
}
17001738

17011739
bool IndexSwiftASTWalker::initIndexSymbol(ExtensionDecl *ExtD, ValueDecl *ExtendedD,
17021740
SourceLoc Loc, IndexSymbol &Info) {
17031741
assert(ExtD && ExtendedD);
1742+
1743+
auto MappedLoc = getMappedLocation(Loc);
1744+
if (!MappedLoc)
1745+
return true;
1746+
17041747
Info.decl = ExtendedD;
1748+
Info.line = MappedLoc->Line;
1749+
Info.column = MappedLoc->Column;
17051750
Info.symInfo = getSymbolInfoForDecl(ExtD);
1751+
17061752
if (Info.symInfo.Kind == SymbolKind::Unknown)
17071753
return true;
17081754

17091755
Info.roles |= (unsigned)SymbolRole::Definition;
1756+
if (MappedLoc->IsGenerated) {
1757+
Info.roles |= (unsigned)SymbolRole::Implicit;
1758+
}
17101759

17111760
if (getNameAndUSR(ExtendedD, ExtD, Info.name, Info.USR))
17121761
return true;
17131762

1714-
std::tie(Info.line, Info.column) = getLineCol(Loc);
17151763
if (auto Group = ExtD->getGroupName())
17161764
Info.group = Group.value();
17171765
return false;
@@ -1832,21 +1880,34 @@ bool IndexSwiftASTWalker::indexComment(const Decl *D) {
18321880
break;
18331881
}
18341882
}
1835-
if (loc.isInvalid())
1883+
1884+
auto mappedLoc = getMappedLocation(loc);
1885+
if (!mappedLoc)
18361886
continue;
1887+
18371888
IndexSymbol Info;
1889+
18381890
Info.decl = nullptr;
1891+
1892+
Info.line = mappedLoc->Line;
1893+
Info.column = mappedLoc->Column;
1894+
18391895
Info.symInfo = SymbolInfo{ SymbolKind::CommentTag, SymbolSubKind::None,
18401896
SymbolLanguage::Swift, SymbolPropertySet() };
1897+
18411898
Info.roles |= (unsigned)SymbolRole::Definition;
1899+
if (mappedLoc->IsGenerated) {
1900+
Info.roles |= (unsigned)SymbolRole::Implicit;
1901+
}
1902+
18421903
Info.name = StringRef();
18431904
SmallString<128> storage;
18441905
{
18451906
llvm::raw_svector_ostream OS(storage);
18461907
OS << "t:" << tagName;
18471908
Info.USR = stringStorage.copyString(OS.str());
18481909
}
1849-
std::tie(Info.line, Info.column) = getLineCol(loc);
1910+
18501911
if (!IdxConsumer.startSourceEntity(Info) || !IdxConsumer.finishSourceEntity(Info.symInfo, Info.roles)) {
18511912
Cancelled = true;
18521913
break;

0 commit comments

Comments
 (0)