Skip to content

Commit 0fc005d

Browse files
authored
Merge pull request #37105 from bnbarham/serialize-offsets
[Serialization] Store offset of decls in .swiftsourceinfo
2 parents 22c0887 + c763ab5 commit 0fc005d

18 files changed

+308
-224
lines changed

Diff for: include/swift/AST/ASTContext.h

+5
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ namespace swift {
7373
class DerivativeAttr;
7474
class DifferentiableAttr;
7575
class ExtensionDecl;
76+
struct ExternalSourceLocs;
7677
class ForeignRepresentationInfo;
7778
class FuncDecl;
7879
class GenericContext;
@@ -1184,6 +1185,10 @@ class ASTContext final {
11841185

11851186
private:
11861187
friend Decl;
1188+
1189+
Optional<ExternalSourceLocs *> getExternalSourceLocs(const Decl *D);
1190+
void setExternalSourceLocs(const Decl *D, ExternalSourceLocs *Locs);
1191+
11871192
Optional<std::pair<RawComment, bool>> getRawComment(const Decl *D);
11881193
void setRawComment(const Decl *D, RawComment RC, bool FromSerialized);
11891194

Diff for: include/swift/AST/Decl.h

+7-8
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ namespace swift {
6262
class DynamicSelfType;
6363
class Type;
6464
class Expr;
65+
struct ExternalSourceLocs;
6566
class CaptureListExpr;
6667
class DeclRefExpr;
6768
class ForeignAsyncConvention;
@@ -688,14 +689,12 @@ class alignas(1 << DeclAlignInBits) Decl {
688689
void operator=(const Decl&) = delete;
689690
SourceLoc getLocFromSource() const;
690691

691-
struct CachedExternalSourceLocs {
692-
SourceLoc Loc;
693-
SourceLoc StartLoc;
694-
SourceLoc EndLoc;
695-
SmallVector<CharSourceRange, 4> DocRanges;
696-
};
697-
mutable CachedExternalSourceLocs const *CachedSerializedLocs = nullptr;
698-
const CachedExternalSourceLocs *getSerializedLocs() const;
692+
/// Returns the serialized locations of this declaration from the
693+
/// corresponding .swiftsourceinfo file. "Empty" (ie. \c BufferID of 0, an
694+
/// invalid \c Loc, and empty \c DocRanges) if either there is no
695+
/// .swiftsourceinfo or the buffer could not be created, eg. if the file
696+
/// no longer exists.
697+
const ExternalSourceLocs *getSerializedLocs() const;
699698

700699
/// Directly set the invalid bit
701700
void setInvalidBit();

Diff for: include/swift/AST/FileUnit.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -164,7 +164,8 @@ class FileUnit : public DeclContext {
164164
return None;
165165
}
166166

167-
virtual Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const {
167+
virtual Optional<ExternalSourceLocs::RawLocs>
168+
getExternalRawLocsForDecl(const Decl *D) const {
168169
return None;
169170
}
170171

Diff for: include/swift/AST/SourceFile.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,8 @@ class SourceFile final : public FileUnit {
399399

400400
Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override;
401401
Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; }
402-
Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const override;
402+
Optional<ExternalSourceLocs::RawLocs>
403+
getExternalRawLocsForDecl(const Decl *D) const override;
403404

404405
/// Returns the synthesized file for this source file, if it exists.
405406
SynthesizedFileUnit *getSynthesizedFile() const { return SynthesizedFile; };

Diff for: include/swift/Basic/BasicSourceInfo.h

+29-12
Original file line numberDiff line numberDiff line change
@@ -15,25 +15,42 @@
1515

1616
#include "swift/Basic/Fingerprint.h"
1717
#include "swift/Basic/LLVM.h"
18+
#include "swift/Basic/SourceLoc.h"
1819
#include "llvm/ADT/PointerIntPair.h"
1920
#include "llvm/Support/Chrono.h"
2021

2122
namespace swift {
2223

2324
class SourceFile;
2425

25-
struct SourcePosition {
26-
uint32_t Line = 0;
27-
uint32_t Column = 0;
28-
bool isValid() const { return Line && Column; }
29-
};
30-
31-
struct BasicDeclLocs {
32-
StringRef SourceFilePath;
33-
SmallVector<std::pair<SourcePosition, uint32_t>, 4> DocRanges;
34-
SourcePosition Loc;
35-
SourcePosition StartLoc;
36-
SourcePosition EndLoc;
26+
struct ExternalSourceLocs {
27+
struct LocationDirective {
28+
uint32_t Offset = 0;
29+
int32_t LineOffset = 0;
30+
uint32_t Length = 0;
31+
StringRef Name;
32+
33+
bool isValid() const { return Length > 0; }
34+
};
35+
36+
struct RawLoc {
37+
uint32_t Offset = 0;
38+
uint32_t Line = 0;
39+
uint32_t Column = 0;
40+
LocationDirective Directive;
41+
};
42+
43+
struct RawLocs {
44+
StringRef SourceFilePath;
45+
SmallVector<std::pair<RawLoc, uint32_t>, 4> DocRanges;
46+
RawLoc Loc;
47+
RawLoc StartLoc;
48+
RawLoc EndLoc;
49+
};
50+
51+
unsigned BufferID = 0;
52+
SourceLoc Loc;
53+
SmallVector<CharSourceRange, 4> DocRanges;
3754
};
3855

3956
class BasicSourceFileInfo {

Diff for: include/swift/Basic/SourceManager.h

+32-15
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ namespace swift {
2424

2525
/// This class manages and owns source buffers.
2626
class SourceManager {
27+
public:
28+
/// A \c #sourceLocation-defined virtual file region, representing the source
29+
/// source after a \c #sourceLocation (or between two). It provides a
30+
/// filename and line offset to be applied to \c SourceLoc's within its
31+
/// \c Range.
32+
struct VirtualFile {
33+
CharSourceRange Range;
34+
std::string Name;
35+
int LineOffset;
36+
};
37+
38+
private:
2739
llvm::SourceMgr LLVMSourceMgr;
2840
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem;
2941
unsigned CodeCompletionBufferID = 0U;
@@ -52,12 +64,6 @@ class SourceManager {
5264
};
5365
ReplacedRangeType ReplacedRange;
5466

55-
// \c #sourceLocation directive handling.
56-
struct VirtualFile {
57-
CharSourceRange Range;
58-
std::string Name;
59-
int LineOffset;
60-
};
6167
std::map<const char *, VirtualFile> VirtualFiles;
6268
mutable std::pair<const char *, const VirtualFile*> CachedVFile = {nullptr, nullptr};
6369

@@ -143,6 +149,10 @@ class SourceManager {
143149
/// Adds a memory buffer to the SourceManager, taking ownership of it.
144150
unsigned addNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer);
145151

152+
/// Add a \c #sourceLocation-defined virtual file region of \p Length.
153+
void createVirtualFile(SourceLoc Loc, StringRef Name, int LineOffset,
154+
unsigned Length);
155+
146156
/// Add a \c #sourceLocation-defined virtual file region.
147157
///
148158
/// By default, this region continues to the end of the buffer.
@@ -275,18 +285,17 @@ class SourceManager {
275285

276286
std::string getLineString(unsigned BufferID, unsigned LineNumber);
277287

288+
/// Retrieve the buffer ID for \p Path, loading if necessary.
289+
unsigned getExternalSourceBufferID(StringRef Path);
290+
278291
SourceLoc getLocFromExternalSource(StringRef Path, unsigned Line, unsigned Col);
279-
private:
292+
293+
/// Retrieve the virtual file for the given \p Loc, or nullptr if none exists.
280294
const VirtualFile *getVirtualFile(SourceLoc Loc) const;
281-
unsigned getExternalSourceBufferId(StringRef Path);
282-
int getLineOffset(SourceLoc Loc) const {
283-
if (auto VFile = getVirtualFile(Loc))
284-
return VFile->LineOffset;
285-
else
286-
return 0;
287-
}
288295

289-
public:
296+
/// Whether or not \p Loc is after a \c #sourceLocation directive, ie. its
297+
/// file, line, and column should be reported using the information in the
298+
/// directive.
290299
bool isLocInVirtualFile(SourceLoc Loc) const {
291300
return getVirtualFile(Loc) != nullptr;
292301
}
@@ -295,6 +304,14 @@ class SourceManager {
295304
/// owned by \p otherManager. Returns an invalid SourceLoc if it cannot be
296305
/// translated.
297306
SourceLoc getLocForForeignLoc(SourceLoc otherLoc, SourceManager &otherMgr);
307+
308+
private:
309+
int getLineOffset(SourceLoc Loc) const {
310+
if (auto VFile = getVirtualFile(Loc))
311+
return VFile->LineOffset;
312+
else
313+
return 0;
314+
}
298315
};
299316

300317
} // end namespace swift

Diff for: include/swift/Serialization/SerializedModuleLoader.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,8 @@ class SerializedASTFile final : public LoadedFile {
392392

393393
Optional<StringRef> getGroupNameByUSR(StringRef USR) const override;
394394

395-
Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const override;
395+
Optional<ExternalSourceLocs::RawLocs>
396+
getExternalRawLocsForDecl(const Decl *D) const override;
396397

397398
void collectAllGroups(SmallVectorImpl<StringRef> &Names) const override;
398399

Diff for: lib/AST/ASTContext.cpp

+18
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,10 @@ struct ASTContext::Implementation {
287287
/// The module loader used to load Clang modules from DWARF.
288288
ClangModuleLoader *TheDWARFModuleLoader = nullptr;
289289

290+
/// Map from Swift declarations to deserialized resolved locations, ie.
291+
/// actual \c SourceLocs that require opening their external buffer.
292+
llvm::DenseMap<const Decl *, ExternalSourceLocs *> ExternalSourceLocs;
293+
290294
/// Map from Swift declarations to raw comments.
291295
llvm::DenseMap<const Decl *, std::pair<RawComment, bool>> RawComments;
292296

@@ -2048,6 +2052,20 @@ ModuleDecl *ASTContext::getStdlibModule(bool loadIfAbsent) {
20482052
return TheStdlibModule;
20492053
}
20502054

2055+
Optional<ExternalSourceLocs *>
2056+
ASTContext::getExternalSourceLocs(const Decl *D) {
2057+
auto Known = getImpl().ExternalSourceLocs.find(D);
2058+
if (Known == getImpl().ExternalSourceLocs.end())
2059+
return None;
2060+
2061+
return Known->second;
2062+
}
2063+
2064+
void ASTContext::setExternalSourceLocs(const Decl *D,
2065+
ExternalSourceLocs *Locs) {
2066+
getImpl().ExternalSourceLocs[D] = Locs;
2067+
}
2068+
20512069
Optional<std::pair<RawComment, bool>> ASTContext::getRawComment(const Decl *D) {
20522070
auto Known = getImpl().RawComments.find(D);
20532071
if (Known == getImpl().RawComments.end())

Diff for: lib/AST/Decl.cpp

+38-24
Original file line numberDiff line numberDiff line change
@@ -610,36 +610,50 @@ case DeclKind::ID: return cast<ID##Decl>(this)->getLocFromSource();
610610
llvm_unreachable("Unknown decl kind");
611611
}
612612

613-
const Decl::CachedExternalSourceLocs *Decl::getSerializedLocs() const {
614-
if (CachedSerializedLocs) {
615-
return CachedSerializedLocs;
616-
}
613+
const ExternalSourceLocs *Decl::getSerializedLocs() const {
614+
auto &Context = getASTContext();
615+
if (auto EL = Context.getExternalSourceLocs(this).getValueOr(nullptr))
616+
return EL;
617+
618+
static ExternalSourceLocs NullLocs{};
619+
617620
auto *File = cast<FileUnit>(getDeclContext()->getModuleScopeContext());
618-
assert(File->getKind() == FileUnitKind::SerializedAST &&
619-
"getSerializedLocs() should only be called on decls in "
620-
"a 'SerializedASTFile'");
621-
auto Locs = File->getBasicLocsForDecl(this);
622-
if (!Locs.hasValue()) {
623-
static const Decl::CachedExternalSourceLocs NullLocs{};
621+
if (File->getKind() != FileUnitKind::SerializedAST)
622+
return &NullLocs;
623+
624+
auto RawLocs = File->getExternalRawLocsForDecl(this);
625+
if (!RawLocs.hasValue()) {
626+
// Don't read .swiftsourceinfo again on failure
627+
Context.setExternalSourceLocs(this, &NullLocs);
624628
return &NullLocs;
625629
}
626-
auto *Result = getASTContext().Allocate<Decl::CachedExternalSourceLocs>();
627-
auto &SM = getASTContext().SourceMgr;
628-
#define CASE(X) \
629-
Result->X = SM.getLocFromExternalSource(Locs->SourceFilePath, Locs->X.Line, \
630-
Locs->X.Column);
631-
CASE(Loc)
632-
CASE(StartLoc)
633-
CASE(EndLoc)
634-
#undef CASE
635630

636-
for (const auto &LineColumnAndLength : Locs->DocRanges) {
637-
auto Start = SM.getLocFromExternalSource(Locs->SourceFilePath,
638-
LineColumnAndLength.first.Line,
639-
LineColumnAndLength.first.Column);
640-
Result->DocRanges.push_back({ Start, LineColumnAndLength.second });
631+
auto &SM = getASTContext().SourceMgr;
632+
unsigned BufferID = SM.getExternalSourceBufferID(RawLocs->SourceFilePath);
633+
if (!BufferID) {
634+
// Don't try open the file again on failure
635+
Context.setExternalSourceLocs(this, &NullLocs);
636+
return &NullLocs;
641637
}
642638

639+
auto ResolveLoc = [&](const ExternalSourceLocs::RawLoc &Raw) -> SourceLoc {
640+
// If the decl had a presumed loc, create its virtual file so that
641+
// getPresumedLineAndColForLoc works from serialized locations as well.
642+
if (Raw.Directive.isValid()) {
643+
auto &LD = Raw.Directive;
644+
SourceLoc Loc = SM.getLocForOffset(BufferID, LD.Offset);
645+
SM.createVirtualFile(Loc, LD.Name, LD.LineOffset, LD.Length);
646+
}
647+
return SM.getLocForOffset(BufferID, Raw.Offset);
648+
};
649+
650+
auto *Result = getASTContext().Allocate<ExternalSourceLocs>();
651+
Result->BufferID = BufferID;
652+
Result->Loc = ResolveLoc(RawLocs->Loc);
653+
for (auto &Range : RawLocs->DocRanges) {
654+
Result->DocRanges.emplace_back(ResolveLoc(Range.first), Range.second);
655+
}
656+
Context.setExternalSourceLocs(this, Result);
643657
return Result;
644658
}
645659

Diff for: lib/AST/Module.cpp

+33-20
Original file line numberDiff line numberDiff line change
@@ -855,37 +855,50 @@ TypeDecl *SourceFile::lookupLocalType(llvm::StringRef mangledName) const {
855855
return nullptr;
856856
}
857857

858-
Optional<BasicDeclLocs>
859-
SourceFile::getBasicLocsForDecl(const Decl *D) const {
858+
Optional<ExternalSourceLocs::RawLocs>
859+
SourceFile::getExternalRawLocsForDecl(const Decl *D) const {
860860
auto *FileCtx = D->getDeclContext()->getModuleScopeContext();
861861
assert(FileCtx == this && "D doesn't belong to this source file");
862862
if (FileCtx != this) {
863863
// D doesn't belong to this file. This shouldn't happen in practice.
864864
return None;
865865
}
866-
if (D->getLoc().isInvalid())
866+
867+
SourceLoc Loc = D->getLoc(/*SerializedOK=*/false);
868+
if (Loc.isInvalid())
867869
return None;
870+
868871
SourceManager &SM = getASTContext().SourceMgr;
869-
BasicDeclLocs Result;
870-
Result.SourceFilePath = SM.getDisplayNameForLoc(D->getLoc());
872+
auto BufferID = SM.findBufferContainingLoc(Loc);
871873

872-
for (const auto &SRC : D->getRawComment(/*SerializedOK*/false).Comments) {
873-
auto LineAndCol = SM.getLineAndColumnInBuffer(SRC.Range.getStart());
874-
Result.DocRanges.push_back(
875-
std::make_pair(SourcePosition{LineAndCol.first, LineAndCol.second},
876-
SRC.Range.getByteLength()));
877-
}
874+
ExternalSourceLocs::RawLocs Result;
875+
auto setLoc = [&](ExternalSourceLocs::RawLoc &RawLoc, SourceLoc Loc) {
876+
if (!Loc.isValid())
877+
return;
878878

879-
auto setLineColumn = [&SM](SourcePosition &Home, SourceLoc Loc) {
880-
if (Loc.isValid()) {
881-
std::tie(Home.Line, Home.Column) = SM.getPresumedLineAndColumnForLoc(Loc);
882-
}
879+
RawLoc.Offset = SM.getLocOffsetInBuffer(Loc, BufferID);
880+
std::tie(RawLoc.Line, RawLoc.Column) = SM.getLineAndColumnInBuffer(Loc);
881+
882+
auto *VF = SM.getVirtualFile(Loc);
883+
if (!VF)
884+
return;
885+
886+
RawLoc.Directive.Offset =
887+
SM.getLocOffsetInBuffer(VF->Range.getStart(), BufferID);
888+
RawLoc.Directive.LineOffset = VF->LineOffset;
889+
RawLoc.Directive.Length = VF->Range.getByteLength();
890+
RawLoc.Directive.Name = StringRef(VF->Name);
883891
};
884-
#define SET(X) setLineColumn(Result.X, D->get##X());
885-
SET(Loc)
886-
SET(StartLoc)
887-
SET(EndLoc)
888-
#undef SET
892+
893+
Result.SourceFilePath = SM.getIdentifierForBuffer(BufferID);
894+
for (const auto &SRC : D->getRawComment(/*SerializedOK=*/false).Comments) {
895+
Result.DocRanges.emplace_back(ExternalSourceLocs::RawLoc(),
896+
SRC.Range.getByteLength());
897+
setLoc(Result.DocRanges.back().first, SRC.Range.getStart());
898+
}
899+
setLoc(Result.Loc, D->getLoc(/*SerializedOK=*/false));
900+
setLoc(Result.StartLoc, D->getStartLoc());
901+
setLoc(Result.EndLoc, D->getEndLoc());
889902
return Result;
890903
}
891904

0 commit comments

Comments
 (0)