Skip to content

Commit 54683ca

Browse files
committed
[SourceKit] Update SyntaxInfo but with lazy parsing in "edit" request
Previously, if the client requests no information from "edit" request, the syntax info wasn't updated. But "expand placeholder" request requires the up-to-date syntax info. rdar://77665805
1 parent da96ef1 commit 54683ca

File tree

3 files changed

+81
-32
lines changed

3 files changed

+81
-32
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// BEGIN main.swift
2+
enum E { case foo, bar }
3+
func foo(x: (E) -> Void) {}
4+
func test() {
5+
foo(x: <#T##(E) -> Void#>)
6+
}
7+
8+
// BEGIN expand.json.in
9+
{
10+
key.request: source.request.editor.expand_placeholder,
11+
key.offset: 23,
12+
key.length: 18,
13+
key.name: "FILENAME"
14+
}
15+
16+
// RUN: %empty-directory(%t)
17+
// RUN: %{python} %utils/split_file.py -o %t %s
18+
19+
// RUN: sed "s#FILENAME#%t/main.swift#" %t/expand.json.in > %t/expand.json
20+
21+
// RUN: %sourcekitd-test \
22+
// RUN: -req=open %t/main.swift -- %t/main.swift == \
23+
// RUN: -req=edit -offset=0 -length=53 -replace="" -req-opts=enablesyntaxmap=0,enablesubstructure=0,enablediagnostics=0 %t/main.swift -- %t/main.swift == \
24+
// RUN: -json-request-path %t/expand.json \
25+
// RUN: | %FileCheck %s
26+
27+
// CHECK: {
28+
// CHECK: key.offset: 19,
29+
// CHECK: key.length: 23,
30+
// CHECK: key.sourcetext: " { <#E#> in\n<#code#>\n}"
31+
// CHECK: }
32+

tools/SourceKit/lib/SwiftLang/SwiftEditor.cpp

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,8 @@ class SwiftDocumentSyntaxInfo {
677677
std::string PrimaryFile;
678678
/// Whether or not the AST stored in the source file is up-to-date or just an
679679
/// artifact of incremental syntax parsing
680-
bool HasUpToDateAST;
680+
bool IncrementalParsingEnabled;
681+
bool IsParsed;
681682

682683
public:
683684
SwiftDocumentSyntaxInfo(const CompilerInvocation &CompInv,
@@ -713,13 +714,16 @@ class SwiftDocumentSyntaxInfo {
713714
Parser->getParser().Context.evaluator);
714715
Parser->getDiagnosticEngine().addConsumer(DiagConsumer);
715716

716-
// If there is a syntax parsing cache, incremental syntax parsing is
717-
// performed and thus the generated AST may not be up-to-date.
718-
HasUpToDateAST = CompInv.getMainFileSyntaxParsingCache() == nullptr;
717+
IncrementalParsingEnabled =
718+
CompInv.getMainFileSyntaxParsingCache() != nullptr;
719+
IsParsed = false;
719720
}
720721

721-
void parse() {
722-
Parser->parse();
722+
void parseIfNeeded() {
723+
if (!IsParsed) {
724+
Parser->parse();
725+
IsParsed = true;
726+
}
723727
}
724728

725729
SourceFile &getSourceFile() {
@@ -738,7 +742,7 @@ class SwiftDocumentSyntaxInfo {
738742
return SM;
739743
}
740744

741-
bool hasUpToDateAST() { return HasUpToDateAST; }
745+
bool isIncrementalParsingEnabled() { return IncrementalParsingEnabled; }
742746

743747
ArrayRef<DiagnosticEntryInfo> getDiagnostics() {
744748
return DiagConsumer.getDiagnosticsForBuffer(BufferID);
@@ -1074,6 +1078,7 @@ struct SwiftEditorDocument::Implementation {
10741078

10751079
std::shared_ptr<SwiftDocumentSyntaxInfo> getSyntaxInfo() {
10761080
llvm::sys::ScopedLock L(AccessMtx);
1081+
SyntaxInfo->parseIfNeeded();
10771082
return SyntaxInfo;
10781083
}
10791084

@@ -1949,9 +1954,10 @@ void SwiftEditorDocument::updateSemaInfo() {
19491954
::updateSemaInfo(SemanticInfo, EditableBuffer);
19501955
}
19511956

1952-
void SwiftEditorDocument::parse(ImmutableTextSnapshotRef Snapshot,
1953-
SwiftLangSupport &Lang, bool BuildSyntaxTree,
1954-
SyntaxParsingCache *SyntaxCache) {
1957+
void SwiftEditorDocument::resetSyntaxInfo(ImmutableTextSnapshotRef Snapshot,
1958+
SwiftLangSupport &Lang,
1959+
bool BuildSyntaxTree,
1960+
SyntaxParsingCache *SyntaxCache) {
19551961
llvm::sys::ScopedLock L(Impl.AccessMtx);
19561962

19571963
assert(Impl.SemanticInfo && "Impl.SemanticInfo must be set");
@@ -1982,15 +1988,14 @@ void SwiftEditorDocument::parse(ImmutableTextSnapshotRef Snapshot,
19821988
// Access to Impl.SyntaxInfo is guarded by Impl.AccessMtx
19831989
Impl.SyntaxInfo.reset(
19841990
new SwiftDocumentSyntaxInfo(CompInv, Snapshot, Args, Impl.FilePath));
1985-
1986-
Impl.SyntaxInfo->parse();
19871991
}
19881992

19891993
static UIdent SemaDiagStage("source.diagnostic.stage.swift.sema");
19901994
static UIdent ParseDiagStage("source.diagnostic.stage.swift.parse");
19911995

19921996
void SwiftEditorDocument::readSyntaxInfo(EditorConsumer &Consumer, bool ReportDiags) {
19931997
llvm::sys::ScopedLock L(Impl.AccessMtx);
1998+
Impl.SyntaxInfo->parseIfNeeded();
19941999

19952000
Impl.ParserDiagnostics = Impl.SyntaxInfo->getDiagnostics();
19962001
if (ReportDiags) {
@@ -2105,8 +2110,8 @@ SwiftEditorDocument::getSyntaxTree() const {
21052110

21062111
std::string SwiftEditorDocument::getFilePath() const { return Impl.FilePath; }
21072112

2108-
bool SwiftEditorDocument::hasUpToDateAST() const {
2109-
return Impl.SyntaxInfo->hasUpToDateAST();
2113+
bool SwiftEditorDocument::isIncrementalParsingEnabled() const {
2114+
return Impl.SyntaxInfo->isIncrementalParsingEnabled();
21102115
}
21112116

21122117
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem>
@@ -2335,7 +2340,7 @@ void SwiftLangSupport::editorOpen(
23352340
EditorDoc = new SwiftEditorDocument(Name, *this, fileSystem);
23362341
Snapshot = EditorDoc->initializeText(
23372342
Buf, Args, Consumer.needsSemanticInfo(), fileSystem);
2338-
EditorDoc->parse(Snapshot, *this, Consumer.syntaxTreeEnabled());
2343+
EditorDoc->resetSyntaxInfo(Snapshot, *this, Consumer.syntaxTreeEnabled());
23392344
if (EditorDocuments->getOrUpdate(Name, *this, EditorDoc)) {
23402345
// Document already exists, re-initialize it. This should only happen
23412346
// if we get OPEN request while the previous document is not closed.
@@ -2349,7 +2354,7 @@ void SwiftLangSupport::editorOpen(
23492354
if (!Snapshot) {
23502355
Snapshot = EditorDoc->initializeText(
23512356
Buf, Args, Consumer.needsSemanticInfo(), fileSystem);
2352-
EditorDoc->parse(Snapshot, *this, Consumer.syntaxTreeEnabled());
2357+
EditorDoc->resetSyntaxInfo(Snapshot, *this, Consumer.syntaxTreeEnabled());
23532358
}
23542359

23552360
if (Consumer.needsSemanticInfo()) {
@@ -2402,7 +2407,7 @@ void verifyIncrementalParse(SwiftEditorDocumentRef EditorDoc,
24022407
SwiftDocumentSyntaxInfo ScratchSyntaxInfo(Invocation,
24032408
EditorDoc->getLatestSnapshot(),
24042409
Args, EditorDoc->getFilePath());
2405-
ScratchSyntaxInfo.parse();
2410+
ScratchSyntaxInfo.parseIfNeeded();
24062411

24072412
// Dump the from-scratch syntax tree
24082413
std::string FromScratchTreeString;
@@ -2507,19 +2512,22 @@ void SwiftLangSupport::editorReplaceText(StringRef Name,
25072512
}
25082513

25092514
// If client doesn't need any information, we doen't need to parse it.
2515+
2516+
2517+
SyntaxParsingCache *SyntaxCachePtr = nullptr;
2518+
if (SyntaxCache.hasValue()) {
2519+
SyntaxCachePtr = SyntaxCache.getPointer();
2520+
}
2521+
EditorDoc->resetSyntaxInfo(Snapshot, *this, Consumer.syntaxTreeEnabled(),
2522+
SyntaxCachePtr);
2523+
25102524
if (!Consumer.documentStructureEnabled() &&
25112525
!Consumer.syntaxMapEnabled() &&
25122526
!Consumer.diagnosticsEnabled() &&
25132527
!Consumer.syntaxTreeEnabled()) {
25142528
return;
25152529
}
25162530

2517-
SyntaxParsingCache *SyntaxCachePtr = nullptr;
2518-
if (SyntaxCache.hasValue()) {
2519-
SyntaxCachePtr = SyntaxCache.getPointer();
2520-
}
2521-
EditorDoc->parse(Snapshot, *this, Consumer.syntaxTreeEnabled(),
2522-
SyntaxCachePtr);
25232531
// Do not report syntactic diagnostics; will be handled in readSemanticInfo.
25242532
EditorDoc->readSyntaxInfo(Consumer, /*ReportDiags=*/false);
25252533

@@ -2578,11 +2586,12 @@ void SwiftLangSupport::editorFormatText(StringRef Name, unsigned Line,
25782586
return;
25792587
}
25802588

2581-
if (!EditorDoc->hasUpToDateAST()) {
2582-
// An up-to-date AST is needed for formatting. If it does not exist, fall
2583-
// back to a full reparse of the file
2584-
EditorDoc->parse(EditorDoc->getLatestSnapshot(), *this,
2585-
/*BuildSyntaxTree=*/true);
2589+
if (EditorDoc->isIncrementalParsingEnabled()) {
2590+
// If incremental parsing is enabled, AST is not updated properly. Fall
2591+
// back to a full reparse of the file.
2592+
EditorDoc->resetSyntaxInfo(EditorDoc->getLatestSnapshot(), *this,
2593+
/*BuildSyntaxTree=*/true,
2594+
/*SyntaxCache=*/nullptr);
25862595
}
25872596

25882597
EditorDoc->formatText(Line, Length, Consumer);
@@ -2616,5 +2625,13 @@ void SwiftLangSupport::editorExpandPlaceholder(StringRef Name, unsigned Offset,
26162625
return;
26172626
}
26182627

2628+
if (EditorDoc->isIncrementalParsingEnabled()) {
2629+
// If incremental parsing is enabled, AST is not updated properly. Fall
2630+
// back to a full reparse of the file.
2631+
EditorDoc->resetSyntaxInfo(EditorDoc->getLatestSnapshot(), *this,
2632+
/*BuildSyntaxTree=*/true,
2633+
/*SyntaxCache=*/nullptr);
2634+
}
2635+
26192636
EditorDoc->expandPlaceholder(Offset, Length, Consumer);
26202637
}

tools/SourceKit/lib/SwiftLang/SwiftLangSupport.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,9 @@ class SwiftEditorDocument :
107107
ImmutableTextSnapshotRef getLatestSnapshot() const;
108108
std::pair<unsigned, unsigned> getLineAndColumnInBuffer(unsigned Offset);
109109

110-
void parse(ImmutableTextSnapshotRef Snapshot, SwiftLangSupport &Lang,
111-
bool BuildSyntaxTree,
112-
swift::SyntaxParsingCache *SyntaxCache = nullptr);
110+
void resetSyntaxInfo(ImmutableTextSnapshotRef Snapshot,
111+
SwiftLangSupport &Lang, bool BuildSyntaxTree,
112+
swift::SyntaxParsingCache *SyntaxCache = nullptr);
113113
void readSyntaxInfo(EditorConsumer &consumer, bool ReportDiags);
114114
void readSemanticInfo(ImmutableTextSnapshotRef Snapshot,
115115
EditorConsumer& Consumer);
@@ -129,7 +129,7 @@ class SwiftEditorDocument :
129129

130130
/// Whether or not the AST stored for this document is up-to-date or just an
131131
/// artifact of incremental syntax parsing
132-
bool hasUpToDateAST() const;
132+
bool isIncrementalParsingEnabled() const;
133133

134134
/// Returns the virtual filesystem associated with this document.
135135
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> getFileSystem() const;

0 commit comments

Comments
 (0)