[CursorInfo] Re-use already built ASTs ahead of currently building ones

Resolves rdar://110344363.
This commit is contained in:
Ben Barham
2023-06-21 18:02:39 -07:00
parent 3676379302
commit 037ddc92ee
2 changed files with 42 additions and 9 deletions

View File

@@ -8,4 +8,6 @@
// RUN: %sourcekitd-test \ // RUN: %sourcekitd-test \
// RUN: -req=open -text-input %t/empty.swift %t/func.swift -- %t/func.swift == \ // RUN: -req=open -text-input %t/empty.swift %t/func.swift -- %t/func.swift == \
// RUN: -req=edit -offset=0 -length=0 -replace="func foo() {}" -req-opts=enablesyntaxmap=0,enablesubstructure=0,enablediagnostics=0 %t/func.swift -- %t/func.swift == \ // RUN: -req=edit -offset=0 -length=0 -replace="func foo() {}" -req-opts=enablesyntaxmap=0,enablesubstructure=0,enablediagnostics=0 %t/func.swift -- %t/func.swift == \
// RUN: -req=cursor -offset=5 %t/func.swift -- %t/func.swift // RUN: -req=cursor -offset=5 %t/func.swift -- %t/func.swift == \
// RUN: -req=edit -offset=0 -length=0 -replace="// some comment\n" -req-opts=enablesyntaxmap=0,enablesubstructure=0,enablediagnostics=0 %t/func.swift -- %t/func.swift == \
// RUN: -req=cursor -offset=21 %t/func.swift -- %t/func.swift

View File

@@ -1219,14 +1219,41 @@ bool ASTBuildOperation::addConsumer(SwiftASTConsumerRef Consumer) {
return true; return true;
} }
/// Returns a build operation that `Consumer` can use, in order of the
/// following:
/// 1. The latest finished build operation that either exactly matches, or
/// can be used with snapshots
/// 2. If none, the latest in-progress build operation with the same
/// conditions
/// 3. `nullptr` otherwise
ASTBuildOperationRef ASTProducer::getBuildOperationForConsumer( ASTBuildOperationRef ASTProducer::getBuildOperationForConsumer(
SwiftASTConsumerRef Consumer, SwiftASTConsumerRef Consumer,
IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem, IntrusiveRefCntPtr<llvm::vfs::FileSystem> FileSystem,
SwiftASTManagerRef Mgr) { SwiftASTManagerRef Mgr) {
ASTBuildOperationRef LatestUsableOp;
Statistic *StatCount = nullptr;
for (auto &BuildOp : llvm::reverse(BuildOperations)) { for (auto &BuildOp : llvm::reverse(BuildOperations)) {
if (BuildOp->isCancelled()) { if (BuildOp->isCancelled())
continue;
// No point checking for a match, we already have one - we're just looking
// for a finished operation that can be used with the file contents of
// `BuildOp` at this point (which we will prefer over an incomplete
// operation, whether that exactly matches or not).
if (LatestUsableOp && !BuildOp->isFinished())
continue;
// Check for an exact match
if (BuildOp->matchesSourceState(FileSystem)) {
LatestUsableOp = BuildOp;
StatCount = &Mgr->Impl.Stats->numASTCacheHits;
if (BuildOp->isFinished())
break;
continue; continue;
} }
// Check for whether the operation can be used taking into account
// snapshots
std::vector<ImmutableTextSnapshotRef> Snapshots; std::vector<ImmutableTextSnapshotRef> Snapshots;
Snapshots.reserve(BuildOp->getFileContents().size()); Snapshots.reserve(BuildOp->getFileContents().size());
for (auto &FileContent : BuildOp->getFileContents()) { for (auto &FileContent : BuildOp->getFileContents()) {
@@ -1234,15 +1261,19 @@ ASTBuildOperationRef ASTProducer::getBuildOperationForConsumer(
Snapshots.push_back(FileContent.Snapshot); Snapshots.push_back(FileContent.Snapshot);
} }
} }
if (BuildOp->matchesSourceState(FileSystem)) {
++Mgr->Impl.Stats->numASTCacheHits; if (Consumer->canUseASTWithSnapshots(Snapshots)) {
return BuildOp; LatestUsableOp = BuildOp;
} else if (Consumer->canUseASTWithSnapshots(Snapshots)) { StatCount = &Mgr->Impl.Stats->numASTsUsedWithSnapshots;
++Mgr->Impl.Stats->numASTsUsedWithSnapshots; if (BuildOp->isFinished())
return BuildOp; break;
} }
} }
return nullptr;
if (StatCount) {
++(*StatCount);
}
return LatestUsableOp;
} }
void ASTProducer::enqueueConsumer( void ASTProducer::enqueueConsumer(