Skip to content

Commit b9810fb

Browse files
committed
[SourceKit] Return the original location for decls within generated code
Pass back the original location (ie. where the macro was expanded, not the location that the generated code would be inserted) for cursor info and indexing. Also mark any declarations/references within generated source as implicit. Resolves rdar://107209132.
1 parent 1d7ef25 commit b9810fb

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)