Skip to content

Commit 91dd9b6

Browse files
Merge pull request #1993 from Microsoft/incrementalCorruption
Fix issue with cancellation causing corruption with source files.
2 parents b277695 + b86ef44 commit 91dd9b6

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

src/compiler/parser.ts

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,6 +736,16 @@ module ts {
736736
return parseSourceFile(sourceFile.fileName, newText, sourceFile.languageVersion, /*syntaxCursor*/ undefined, /*setNodeParents*/ true)
737737
}
738738

739+
// Make sure we're not trying to incrementally update a source file more than once. Once
740+
// we do an update the original source file is considered unusbale from that point onwards.
741+
//
742+
// This is because we do incremental parsing in-place. i.e. we take nodes from the old
743+
// tree and give them new positions and parents. From that point on, trusting the old
744+
// tree at all is not possible as far too much of it may violate invariants.
745+
var incrementalSourceFile = <IncrementalNode><Node>sourceFile;
746+
Debug.assert(!incrementalSourceFile.hasBeenIncrementallyParsed);
747+
incrementalSourceFile.hasBeenIncrementallyParsed = true;
748+
739749
var oldText = sourceFile.text;
740750
var syntaxCursor = createSyntaxCursor(sourceFile);
741751

@@ -774,7 +784,7 @@ module ts {
774784
//
775785
// Also, mark any syntax elements that intersect the changed span. We know, up front,
776786
// that we cannot reuse these elements.
777-
updateTokenPositionsAndMarkElements(<IncrementalNode><Node>sourceFile,
787+
updateTokenPositionsAndMarkElements(incrementalSourceFile,
778788
changeRange.span.start, textSpanEnd(changeRange.span), textSpanEnd(textChangeRangeNewSpan(changeRange)), delta, oldText, newText, aggressiveChecks);
779789

780790
// Now that we've set up our internal incremental state just proceed and parse the
@@ -815,6 +825,7 @@ module ts {
815825
}
816826

817827
interface IncrementalNode extends Node, IncrementalElement {
828+
hasBeenIncrementallyParsed: boolean
818829
}
819830

820831
interface IncrementalNodeArray extends NodeArray<IncrementalNode>, IncrementalElement {

src/services/services.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2022,6 +2022,12 @@ module ts {
20222022
return;
20232023
}
20242024

2025+
// IMPORTANT - It is critical from this moment onward that we do not check
2026+
// cancellation tokens. We are about to mutate source files from a previous program
2027+
// instance. If we cancel midway through, we may end up in an inconsistent state where
2028+
// the program points to old source files that have been invalidated because of
2029+
// incremental parsing.
2030+
20252031
var oldSettings = program && program.getCompilerOptions();
20262032
var newSettings = hostCache.compilationSettings();
20272033
var changesInCompilationSettingsAffectSyntax = oldSettings && oldSettings.target !== newSettings.target;
@@ -2056,8 +2062,6 @@ module ts {
20562062
return;
20572063

20582064
function getOrCreateSourceFile(fileName: string): SourceFile {
2059-
cancellationToken.throwIfCancellationRequested();
2060-
20612065
// The program is asking for this file, check first if the host can locate it.
20622066
// If the host can not locate the file, then it does not exist. return undefined
20632067
// to the program to allow reporting of errors for missing files.
@@ -5363,9 +5367,6 @@ module ts {
53635367
cancellationToken.throwIfCancellationRequested();
53645368

53655369
var fileContents = sourceFile.text;
5366-
5367-
cancellationToken.throwIfCancellationRequested();
5368-
53695370
var result: TodoComment[] = [];
53705371

53715372
if (descriptors.length > 0) {

0 commit comments

Comments
 (0)