Skip to content

Commit df3350c

Browse files
committed
[Serialization] Store offset of decls in .swiftsourceinfo
Rather than calculate the offset from the line and column by reading the source file, just store the offset to begin with. Since the location is used through `getLoc()`, also store the *original* location rather than the presumed. Add line directive information so that the presumed location can be retrieved if needed. Move the serialized location cache out of `Decl` and into `ASTContext` since very few will actually have their locations deserialized. Actually use that cache - the old one was never actually written to.
1 parent c1cb50f commit df3350c

File tree

16 files changed

+276
-183
lines changed

16 files changed

+276
-183
lines changed

include/swift/AST/ASTContext.h

Lines changed: 5 additions & 0 deletions
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 ExternalDeclLocs;
7677
class ForeignRepresentationInfo;
7778
class FuncDecl;
7879
class GenericContext;
@@ -1170,6 +1171,10 @@ class ASTContext final {
11701171

11711172
private:
11721173
friend Decl;
1174+
1175+
Optional<ExternalDeclLocs *> getExternalLocs(const Decl *D);
1176+
void setExternalLocs(const Decl *D, ExternalDeclLocs *Locs);
1177+
11731178
Optional<std::pair<RawComment, bool>> getRawComment(const Decl *D);
11741179
void setRawComment(const Decl *D, RawComment RC, bool FromSerialized);
11751180

include/swift/AST/Decl.h

Lines changed: 11 additions & 9 deletions
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 ExternalDeclLocs;
6566
class CaptureListExpr;
6667
class DeclRefExpr;
6768
class ForeignAsyncConvention;
@@ -686,16 +687,8 @@ class alignas(1 << DeclAlignInBits) Decl {
686687

687688
Decl(const Decl&) = delete;
688689
void operator=(const Decl&) = delete;
689-
SourceLoc getLocFromSource() const;
690690

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;
691+
SourceLoc getLocFromSource() const;
699692

700693
/// Directly set the invalid bit
701694
void setInvalidBit();
@@ -807,6 +800,15 @@ class alignas(1 << DeclAlignInBits) Decl {
807800
/// in diagnostics.
808801
SourceLoc getLoc(bool SerializedOK = true) const;
809802

803+
/// Returns the serialized locations of this declaration from the
804+
/// corresponding .swiftsourceinfo file. Empty if it is within the current
805+
/// module and thus does not have any .swiftsourceinfo.
806+
///
807+
/// By default the locations are simple file, offset, line, and column. To
808+
/// resolve these into \c SourceLocs, set \p Resolve to \c true. Note that
809+
/// this must load the external file, hence being off by default.
810+
const ExternalDeclLocs &getSerializedLocs(bool Resolve = false) const;
811+
810812
/// Returns the source range of the entire declaration.
811813
SourceRange getSourceRange() const;
812814

include/swift/AST/FileUnit.h

Lines changed: 2 additions & 1 deletion
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<BasicDeclPositions>
168+
getBasicPositionsForDecl(const Decl *D) const {
168169
return None;
169170
}
170171

include/swift/AST/SourceFile.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,8 @@ class SourceFile final : public FileUnit {
407407

408408
Identifier getDiscriminatorForPrivateValue(const ValueDecl *D) const override;
409409
Identifier getPrivateDiscriminator() const { return PrivateDiscriminator; }
410-
Optional<BasicDeclLocs> getBasicLocsForDecl(const Decl *D) const override;
410+
Optional<BasicDeclPositions>
411+
getBasicPositionsForDecl(const Decl *D) const override;
411412

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

include/swift/Basic/BasicSourceInfo.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,48 @@
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

26+
struct LocationDirective {
27+
uint32_t Offset = 0;
28+
int32_t LineOffset = 0;
29+
uint32_t Length = 0;
30+
StringRef Name;
31+
32+
bool isValid() const { return Length > 0; }
33+
};
34+
2535
struct SourcePosition {
36+
uint32_t Offset = 0;
2637
uint32_t Line = 0;
2738
uint32_t Column = 0;
39+
LocationDirective Directive;
40+
2841
bool isValid() const { return Line && Column; }
2942
};
3043

31-
struct BasicDeclLocs {
44+
struct BasicDeclPositions {
3245
StringRef SourceFilePath;
3346
SmallVector<std::pair<SourcePosition, uint32_t>, 4> DocRanges;
3447
SourcePosition Loc;
3548
SourcePosition StartLoc;
3649
SourcePosition EndLoc;
3750
};
3851

52+
struct ExternalDeclLocs {
53+
unsigned BufferID = 0;
54+
SourceLoc Loc;
55+
SmallVector<CharSourceRange, 4> DocRanges;
56+
BasicDeclPositions *Positions = nullptr;
57+
bool Resolved = false;
58+
};
59+
3960
class BasicSourceFileInfo {
4061
/// If this is non-null, fields other than 'FilePath' hasn't been populated.
4162
/// The 'getInt()' part indicates this instance is constructed with a

include/swift/Basic/SourceManager.h

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,13 @@
2222

2323
namespace swift {
2424

25+
// \c #sourceLocation directive handling.
26+
struct VirtualFile {
27+
CharSourceRange Range;
28+
std::string Name;
29+
int LineOffset;
30+
};
31+
2532
/// This class manages and owns source buffers.
2633
class SourceManager {
2734
llvm::SourceMgr LLVMSourceMgr;
@@ -52,12 +59,6 @@ class SourceManager {
5259
};
5360
ReplacedRangeType ReplacedRange;
5461

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

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

147+
/// Add a \c #sourceLocation-defined virtual file region of \p Length.
148+
void createVirtualFile(SourceLoc Loc, StringRef Name, int LineOffset,
149+
unsigned Length);
150+
146151
/// Add a \c #sourceLocation-defined virtual file region.
147152
///
148153
/// By default, this region continues to the end of the buffer.
@@ -275,18 +280,21 @@ class SourceManager {
275280

276281
std::string getLineString(unsigned BufferID, unsigned LineNumber);
277282

283+
/// Retrieve the buffer ID for \p Path, loading if necessary.
284+
unsigned getExternalSourceBufferID(StringRef Path);
285+
278286
SourceLoc getLocFromExternalSource(StringRef Path, unsigned Line, unsigned Col);
279-
private:
287+
288+
/// Retrieve the virtual file for the given \p Loc, or nullptr if none exists.
289+
///
290+
/// A virtual file represents the source after a \c #sourceLocation (or
291+
/// between two), providing a filename and line offset to be applied to the
292+
/// given \p Loc.
280293
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-
}
288294

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

300316
} // end namespace swift

include/swift/Serialization/SerializedModuleLoader.h

Lines changed: 2 additions & 1 deletion
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<BasicDeclPositions>
396+
getBasicPositionsForDecl(const Decl *D) const override;
396397

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

lib/AST/ASTContext.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,9 @@ struct ASTContext::Implementation {
284284
/// The module loader used to load Clang modules from DWARF.
285285
ClangModuleLoader *TheDWARFModuleLoader = nullptr;
286286

287+
/// Map from Swift declarations to deserialized locations
288+
llvm::DenseMap<const Decl *, ExternalDeclLocs *> ExternalLocs;
289+
287290
/// Map from Swift declarations to raw comments.
288291
llvm::DenseMap<const Decl *, std::pair<RawComment, bool>> RawComments;
289292

@@ -2020,6 +2023,18 @@ ModuleDecl *ASTContext::getStdlibModule(bool loadIfAbsent) {
20202023
return TheStdlibModule;
20212024
}
20222025

2026+
Optional<ExternalDeclLocs *> ASTContext::getExternalLocs(const Decl *D) {
2027+
auto Known = getImpl().ExternalLocs.find(D);
2028+
if (Known == getImpl().ExternalLocs.end())
2029+
return None;
2030+
2031+
return Known->second;
2032+
}
2033+
2034+
void ASTContext::setExternalLocs(const Decl *D, ExternalDeclLocs *Locs) {
2035+
getImpl().ExternalLocs[D] = Locs;
2036+
}
2037+
20232038
Optional<std::pair<RawComment, bool>> ASTContext::getRawComment(const Decl *D) {
20242039
auto Known = getImpl().RawComments.find(D);
20252040
if (Known == getImpl().RawComments.end())

lib/AST/Decl.cpp

Lines changed: 51 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -610,37 +610,58 @@ 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-
}
617-
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{};
624-
return &NullLocs;
625-
}
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
613+
const ExternalDeclLocs &Decl::getSerializedLocs(bool Resolve) const {
614+
auto &Context = getASTContext();
615+
ExternalDeclLocs *Result = nullptr;
616+
if (auto EL = Context.getExternalLocs(this)) {
617+
Result = *EL;
618+
} else {
619+
static ExternalDeclLocs NullLocs{};
620+
auto *File = cast<FileUnit>(getDeclContext()->getModuleScopeContext());
621+
if (File->getKind() != FileUnitKind::SerializedAST)
622+
return NullLocs;
623+
624+
auto Positions = File->getBasicPositionsForDecl(this);
625+
if (!Positions.hasValue()) {
626+
Result = &NullLocs;
627+
} else {
628+
Result = getASTContext().Allocate<ExternalDeclLocs>();
629+
Result->Positions = getASTContext().AllocateObjectCopy(*Positions);
630+
}
631+
Context.setExternalLocs(this, Result);
632+
}
633+
634+
// Not all callers need SourceLoc's. Creating them requires loading the file,
635+
// so avoid that where we can.
636+
if (Result->Positions && Resolve && !Result->Resolved) {
637+
auto &SM = getASTContext().SourceMgr;
638+
auto *Positions = Result->Positions;
639+
640+
auto ResolveLoc = [&](const SourcePosition &Pos) -> SourceLoc {
641+
// If the decl had a presumed loc, create its virtual file so that
642+
// getPresumedLineAndColForLoc works from serialized locations as well.
643+
if (Pos.Directive.isValid()) {
644+
auto &SL = Pos.Directive;
645+
SourceLoc Loc = SM.getLocForOffset(Result->BufferID, SL.Offset);
646+
SM.createVirtualFile(Loc, SL.Name, SL.LineOffset, SL.Length);
647+
}
648+
return SM.getLocForOffset(Result->BufferID, Pos.Offset);
649+
};
635650

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 });
641-
}
651+
Result->BufferID = SM.getExternalSourceBufferID(Positions->SourceFilePath);
642652

643-
return Result;
653+
// File might not exist since it could have moved since .swiftsourceinfo
654+
// was created.
655+
if (Result->BufferID) {
656+
Result->Loc = ResolveLoc(Positions->Loc);
657+
for (auto &Range : Positions->DocRanges) {
658+
Result->DocRanges.emplace_back(ResolveLoc(Range.first), Range.second);
659+
}
660+
}
661+
662+
Result->Resolved = true;
663+
}
664+
return *Result;
644665
}
645666

646667
StringRef Decl::getAlternateModuleName() const {
@@ -683,7 +704,7 @@ static_assert(sizeof(checkSourceLocType(&ID##Decl::getLoc)) == 2, \
683704
case FileUnitKind::SerializedAST: {
684705
if (!SerializedOK)
685706
return SourceLoc();
686-
return getSerializedLocs()->Loc;
707+
return getSerializedLocs(/*Resolve=*/true).Loc;
687708
}
688709
case FileUnitKind::Builtin:
689710
case FileUnitKind::Synthesized:

0 commit comments

Comments
 (0)