Skip to content

Commit fee7f97

Browse files
committed
Retain ancestor projects and references till open file is present
Also remove unnecessary program update when doing gc on projects
1 parent 812c9bc commit fee7f97

File tree

28 files changed

+535
-373
lines changed

28 files changed

+535
-373
lines changed

internal/compiler/program.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,8 +148,8 @@ func (p *Program) GetResolvedProjectReferences() []*tsoptions.ParsedCommandLine
148148
return p.projectReferenceFileMapper.getResolvedProjectReferences()
149149
}
150150

151-
func (p *Program) ForEachResolvedProjectReference(fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int)) {
152-
p.projectReferenceFileMapper.forEachResolvedProjectReference(fn)
151+
func (p *Program) ForEachResolvedProjectReference(fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) bool) bool {
152+
return p.projectReferenceFileMapper.forEachResolvedProjectReference(fn)
153153
}
154154

155155
func (p *Program) ForEachResolvedProjectReferenceInChildConfig(
@@ -913,13 +913,13 @@ func (p *Program) verifyProjectReferences() {
913913
p.programDiagnostics = append(p.programDiagnostics, diag)
914914
}
915915

916-
p.ForEachResolvedProjectReference(func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) {
916+
p.ForEachResolvedProjectReference(func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) bool {
917917
ref := parent.ProjectReferences()[index]
918918
// !!! Deprecated in 5.0 and removed since 5.5
919919
// verifyRemovedProjectReference(ref, parent, index);
920920
if config == nil {
921921
createDiagnosticForReference(parent, index, diagnostics.File_0_not_found, ref.Path)
922-
return
922+
return false
923923
}
924924
refOptions := config.CompilerOptions()
925925
if !refOptions.Composite.IsTrue() || refOptions.NoEmit.IsTrue() {
@@ -936,6 +936,7 @@ func (p *Program) verifyProjectReferences() {
936936
createDiagnosticForReference(parent, index, diagnostics.Cannot_write_file_0_because_it_will_overwrite_tsbuildinfo_file_generated_by_referenced_project_1, buildInfoFileName, ref.Path)
937937
p.hasEmitBlockingDiagnostics.Add(p.toPath(buildInfoFileName))
938938
}
939+
return false
939940
})
940941
}
941942

internal/compiler/projectreferencefilemapper.go

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,18 +110,15 @@ func (mapper *projectReferenceFileMapper) getResolvedReferenceFor(path tspath.Pa
110110
}
111111

112112
func (mapper *projectReferenceFileMapper) forEachResolvedProjectReference(
113-
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int),
114-
) {
113+
fn func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) bool,
114+
) bool {
115115
if mapper.opts.Config.ConfigFile == nil {
116-
return
116+
return false
117117
}
118118
seenRef := collections.NewSetWithSizeHint[tspath.Path](len(mapper.referencesInConfigFile))
119119
seenRef.Add(mapper.opts.Config.ConfigFile.SourceFile.Path())
120120
refs := mapper.referencesInConfigFile[mapper.opts.Config.ConfigFile.SourceFile.Path()]
121-
mapper.forEachResolvedReferenceWorker(refs, func(path tspath.Path, config *tsoptions.ParsedCommandLine, parent *tsoptions.ParsedCommandLine, index int) bool {
122-
fn(path, config, parent, index)
123-
return false
124-
}, mapper.opts.Config, seenRef)
121+
return mapper.forEachResolvedReferenceWorker(refs, fn, mapper.opts.Config, seenRef)
125122
}
126123

127124
func (mapper *projectReferenceFileMapper) forEachResolvedReferenceWorker(

internal/project/configfileregistrybuilder.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,24 @@ func (c *configFileRegistryBuilder) getConfigFileNameForFile(fileName string, pa
533533
return configName
534534
}
535535

536+
func (c *configFileRegistryBuilder) forEachConfigFileNameFor(fileName string, path tspath.Path, cb func(configFileName string)) {
537+
if isDynamicFileName(fileName) {
538+
return
539+
}
540+
541+
if entry, ok := c.configFileNames.Get(path); ok {
542+
configFileName := entry.Value().nearestConfigFileName
543+
for configFileName != "" {
544+
cb(configFileName)
545+
if ancestorConfigName, found := entry.Value().ancestors[configFileName]; found {
546+
configFileName = ancestorConfigName
547+
} else {
548+
return
549+
}
550+
}
551+
}
552+
}
553+
536554
func (c *configFileRegistryBuilder) getAncestorConfigFileName(fileName string, path tspath.Path, configFileName string, logger *logging.LogTree) string {
537555
if isDynamicFileName(fileName) {
538556
return ""
@@ -542,6 +560,7 @@ func (c *configFileRegistryBuilder) getAncestorConfigFileName(fileName string, p
542560
if !ok {
543561
return ""
544562
}
563+
545564
if ancestorConfigName, found := entry.Value().ancestors[configFileName]; found {
546565
return ancestorConfigName
547566
}

internal/project/projectcollectionbuilder.go

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,15 +255,65 @@ func (b *ProjectCollectionBuilder) DidChangeFiles(summary FileChangeSummary, log
255255
var toRemoveProjects collections.Set[tspath.Path]
256256
openFileResult := b.ensureConfiguredProjectAndAncestorsForFile(fileName, path, logger)
257257
b.configuredProjects.Range(func(entry *dirty.SyncMapEntry[tspath.Path, *Project]) bool {
258-
toRemoveProjects.Add(entry.Value().configFilePath)
259-
b.updateProgram(entry, logger)
258+
toRemoveProjects.Add(entry.Key())
260259
return true
261260
})
261+
var isReferencedBy func(project *Project, refPath tspath.Path, seenProjects *collections.Set[*Project]) bool
262+
isReferencedBy = func(project *Project, refPath tspath.Path, seenProjects *collections.Set[*Project]) bool {
263+
if !seenProjects.AddIfAbsent(project) {
264+
return false
265+
}
266+
267+
if project.potentialProjectReferences != nil {
268+
for potentialRef := range project.potentialProjectReferences.Keys() {
269+
if potentialRef == refPath {
270+
return true
271+
}
272+
}
273+
for potentialRef := range project.potentialProjectReferences.Keys() {
274+
if refProject, foundRef := b.configuredProjects.Load(potentialRef); foundRef && isReferencedBy(refProject.Value(), refPath, seenProjects) {
275+
return true
276+
}
277+
}
278+
} else if program := project.GetProgram(); program != nil && program.ForEachResolvedProjectReference(func(referencePath tspath.Path, _ *tsoptions.ParsedCommandLine, _ *tsoptions.ParsedCommandLine, _ int) bool {
279+
return referencePath == refPath
280+
}) {
281+
return true
282+
}
283+
return false
284+
}
285+
286+
retainProjectAndReferences := func(project *Project) {
287+
// Retain project
288+
toRemoveProjects.Delete(project.configFilePath)
289+
if program := project.GetProgram(); program != nil {
290+
program.ForEachResolvedProjectReference(func(referencePath tspath.Path, _ *tsoptions.ParsedCommandLine, _ *tsoptions.ParsedCommandLine, _ int) bool {
291+
if _, ok := b.configuredProjects.Load(referencePath); ok {
292+
toRemoveProjects.Delete(referencePath)
293+
}
294+
return false
295+
})
296+
}
297+
}
298+
299+
retainDefaultConfiguredProject := func(openFile string, openFilePath tspath.Path, project *Project) {
300+
// Retain project and its references
301+
retainProjectAndReferences(project)
302+
303+
// Retain all the ancestor projects
304+
b.configFileRegistryBuilder.forEachConfigFileNameFor(openFile, openFilePath, func(configFileName string) {
305+
if ancestor := b.findOrCreateProject(configFileName, b.toPath(configFileName), projectLoadKindFind, logger); ancestor != nil {
306+
retainProjectAndReferences(ancestor.Value())
307+
}
308+
})
309+
}
262310

263311
var inferredProjectFiles []string
264312
for _, overlay := range b.fs.overlays {
265-
if p := b.findDefaultConfiguredProject(overlay.FileName(), b.toPath(overlay.FileName())); p != nil {
266-
toRemoveProjects.Delete(p.Value().configFilePath)
313+
openFile := overlay.FileName()
314+
openFilePath := b.toPath(openFile)
315+
if p := b.findDefaultConfiguredProject(openFile, openFilePath); p != nil {
316+
retainDefaultConfiguredProject(openFile, openFilePath, p.Value())
267317
} else {
268318
inferredProjectFiles = append(inferredProjectFiles, overlay.FileName())
269319
}
@@ -591,8 +641,6 @@ func (b *ProjectCollectionBuilder) findDefaultConfiguredProject(fileName string,
591641
func (b *ProjectCollectionBuilder) ensureConfiguredProjectAndAncestorsForFile(fileName string, path tspath.Path, logger *logging.LogTree) searchResult {
592642
result := b.findOrCreateDefaultConfiguredProjectForFile(fileName, path, projectLoadKindCreate, logger)
593643
if result.project != nil && b.openedFiles.Has(path) {
594-
// TODO!!! sheetal - keep these alive as well along with default projects
595-
// !!! sheetal we want to keep referenced projects if any as well alive so they can be used for FAR later
596644
b.createAncestorTree(fileName, path, &result, logger)
597645
}
598646
return result
@@ -1040,8 +1088,9 @@ func (b *ProjectCollectionBuilder) deleteConfiguredProject(project dirty.Value[*
10401088
logger.Log("Deleting configured project: " + project.Value().configFileName)
10411089
}
10421090
if program := project.Value().Program; program != nil {
1043-
program.ForEachResolvedProjectReference(func(referencePath tspath.Path, config *tsoptions.ParsedCommandLine, _ *tsoptions.ParsedCommandLine, _ int) {
1091+
program.ForEachResolvedProjectReference(func(referencePath tspath.Path, config *tsoptions.ParsedCommandLine, _ *tsoptions.ParsedCommandLine, _ int) bool {
10441092
b.configFileRegistryBuilder.releaseConfigForProject(referencePath, projectPath)
1093+
return false
10451094
})
10461095
}
10471096
b.configFileRegistryBuilder.releaseConfigForProject(projectPath, projectPath)

internal/project/session.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,6 @@ func (s *Session) GetLanguageServiceAndProjectsForFile(ctx context.Context, uri
450450
}
451451

452452
func (s *Session) GetProjectsForFile(ctx context.Context, uri lsproto.DocumentUri) ([]*Project, error) {
453-
// !!! sheetal : should not retain this project? probably
454453
snapshot := s.getSnapshot(
455454
ctx,
456455
snapshotChangeRequest{ensureDefaultProjectForURIs: []lsproto.DocumentUri{uri}},

internal/project/snapshot.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ func (s *Snapshot) Clone(ctx context.Context, change SnapshotChange, overlays ma
321321
removedFiles := 0
322322
fs.diskFiles.Range(func(entry *dirty.SyncMapEntry[tspath.Path, *diskFile]) bool {
323323
for _, project := range projectCollection.Projects() {
324-
if project.host.seenFiles.Has(entry.Key()) {
324+
if project.host != nil && project.host.seenFiles.Has(entry.Key()) {
325325
return true
326326
}
327327
}

testdata/baselines/reference/lspservertests/declarationMaps/rename-before-project-is-built.js

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -64,25 +64,15 @@ Projects::
6464
[/user/username/projects/myproject/dependency/tsconfig.json] *new*
6565
/user/username/projects/myproject/dependency/FnS.ts
6666
[/user/username/projects/myproject/tsconfig.json] *new*
67-
/user/username/projects/myproject/dependency/FnS.ts
68-
/user/username/projects/myproject/main/main.ts
6967
Open Files::
7068
[/user/username/projects/myproject/dependency/FnS.ts] *new*
7169
/user/username/projects/myproject/dependency/tsconfig.json (default)
72-
/user/username/projects/myproject/tsconfig.json
7370
Config::
7471
[/user/username/projects/myproject/dependency/tsconfig.json] *new*
7572
RetainingProjects:
7673
/user/username/projects/myproject/dependency/tsconfig.json
77-
/user/username/projects/myproject/tsconfig.json
7874
RetainingOpenFiles:
7975
/user/username/projects/myproject/dependency/fns.ts
80-
[/user/username/projects/myproject/main/tsconfig.json] *new*
81-
RetainingProjects:
82-
/user/username/projects/myproject/tsconfig.json
83-
[/user/username/projects/myproject/tsconfig.json] *new*
84-
RetainingProjects:
85-
/user/username/projects/myproject/tsconfig.json
8676
Config File Names::
8777
[/user/username/projects/myproject/dependency/fns.ts] *new*
8878
NearestConfigFileName: /user/username/projects/myproject/dependency/tsconfig.json
@@ -103,26 +93,20 @@ Config File Names::
10393
Projects::
10494
[/user/username/projects/myproject/dependency/tsconfig.json]
10595
/user/username/projects/myproject/dependency/FnS.ts
106-
[/user/username/projects/myproject/tsconfig.json] *deleted*
107-
/user/username/projects/myproject/dependency/FnS.ts
108-
/user/username/projects/myproject/main/main.ts
96+
[/user/username/projects/myproject/tsconfig.json]
10997
[/user/username/projects/random/tsconfig.json] *new*
11098
/user/username/projects/random/random.ts
11199
Open Files::
112-
[/user/username/projects/myproject/dependency/FnS.ts] *modified*
100+
[/user/username/projects/myproject/dependency/FnS.ts]
113101
/user/username/projects/myproject/dependency/tsconfig.json (default)
114-
/user/username/projects/myproject/tsconfig.json *deleted*
115102
[/user/username/projects/random/random.ts] *new*
116103
/user/username/projects/random/tsconfig.json (default)
117104
Config::
118-
[/user/username/projects/myproject/dependency/tsconfig.json] *modified*
119-
RetainingProjects: *modified*
105+
[/user/username/projects/myproject/dependency/tsconfig.json]
106+
RetainingProjects:
120107
/user/username/projects/myproject/dependency/tsconfig.json
121-
/user/username/projects/myproject/tsconfig.json *deleted*
122108
RetainingOpenFiles:
123109
/user/username/projects/myproject/dependency/fns.ts
124-
[/user/username/projects/myproject/main/tsconfig.json] *deleted*
125-
[/user/username/projects/myproject/tsconfig.json] *deleted*
126110
[/user/username/projects/random/tsconfig.json] *new*
127111
RetainingProjects:
128112
/user/username/projects/random/tsconfig.json
@@ -149,13 +133,68 @@ Config File Names::
149133
"newName": "?"
150134
}
151135
}
136+
Projects::
137+
[/user/username/projects/myproject/dependency/tsconfig.json]
138+
/user/username/projects/myproject/dependency/FnS.ts
139+
[/user/username/projects/myproject/main/tsconfig.json] *new*
140+
/user/username/projects/myproject/dependency/FnS.ts
141+
/user/username/projects/myproject/main/main.ts
142+
[/user/username/projects/myproject/tsconfig.json] *modified*
143+
/user/username/projects/myproject/dependency/FnS.ts *new*
144+
/user/username/projects/myproject/main/main.ts *new*
145+
[/user/username/projects/random/tsconfig.json]
146+
/user/username/projects/random/random.ts
147+
Open Files::
148+
[/user/username/projects/myproject/dependency/FnS.ts] *modified*
149+
/user/username/projects/myproject/dependency/tsconfig.json (default)
150+
/user/username/projects/myproject/main/tsconfig.json *new*
151+
/user/username/projects/myproject/tsconfig.json *new*
152+
[/user/username/projects/random/random.ts]
153+
/user/username/projects/random/tsconfig.json (default)
154+
Config::
155+
[/user/username/projects/myproject/dependency/tsconfig.json] *modified*
156+
RetainingProjects: *modified*
157+
/user/username/projects/myproject/dependency/tsconfig.json
158+
/user/username/projects/myproject/main/tsconfig.json *new*
159+
/user/username/projects/myproject/tsconfig.json *new*
160+
RetainingOpenFiles:
161+
/user/username/projects/myproject/dependency/fns.ts
162+
[/user/username/projects/myproject/main/tsconfig.json] *new*
163+
RetainingProjects:
164+
/user/username/projects/myproject/main/tsconfig.json
165+
/user/username/projects/myproject/tsconfig.json
166+
RetainingOpenFiles:
167+
/user/username/projects/myproject/main/main.ts
168+
[/user/username/projects/myproject/tsconfig.json] *new*
169+
RetainingProjects:
170+
/user/username/projects/myproject/tsconfig.json
171+
[/user/username/projects/random/tsconfig.json]
172+
RetainingProjects:
173+
/user/username/projects/random/tsconfig.json
174+
RetainingOpenFiles:
175+
/user/username/projects/random/random.ts
152176
// === /user/username/projects/myproject/dependency/FnS.ts ===
153177
// export function fn1() { }
154178
// export function fn2() { }
155179
// export function /*RENAME*/[|fn3RENAME|]() { }
156180
// export function fn4() { }
157181
// export function fn5() { }
158182
//
183+
184+
// === /user/username/projects/myproject/main/main.ts ===
185+
// import {
186+
// fn1,
187+
// fn2,
188+
// [|fn3RENAME|],
189+
// fn4,
190+
// fn5
191+
// } from "../decls/FnS";
192+
//
193+
// fn1();
194+
// fn2();
195+
// [|fn3RENAME|]();
196+
// fn4();
197+
// fn5();
159198
{
160199
"method": "textDocument/didClose",
161200
"params": {
@@ -167,6 +206,8 @@ Config File Names::
167206
Open Files::
168207
[/user/username/projects/myproject/dependency/FnS.ts]
169208
/user/username/projects/myproject/dependency/tsconfig.json (default)
209+
/user/username/projects/myproject/main/tsconfig.json
210+
/user/username/projects/myproject/tsconfig.json
170211
[/user/username/projects/random/random.ts] *closed*
171212
{
172213
"method": "textDocument/didOpen",
@@ -182,6 +223,8 @@ Open Files::
182223
Open Files::
183224
[/user/username/projects/myproject/dependency/FnS.ts]
184225
/user/username/projects/myproject/dependency/tsconfig.json (default)
226+
/user/username/projects/myproject/main/tsconfig.json
227+
/user/username/projects/myproject/tsconfig.json
185228
[/user/username/projects/random/random.ts] *new*
186229
/user/username/projects/random/tsconfig.json (default)
187230
{
@@ -220,13 +263,26 @@ Open Files::
220263
Projects::
221264
[/user/username/projects/myproject/dependency/tsconfig.json] *deleted*
222265
/user/username/projects/myproject/dependency/FnS.ts
266+
[/user/username/projects/myproject/main/tsconfig.json] *deleted*
267+
/user/username/projects/myproject/dependency/FnS.ts
268+
/user/username/projects/myproject/main/main.ts
269+
[/user/username/projects/myproject/tsconfig.json] *deleted*
270+
/user/username/projects/myproject/dependency/FnS.ts
271+
/user/username/projects/myproject/main/main.ts
223272
[/user/username/projects/random/tsconfig.json]
224273
/user/username/projects/random/random.ts
225274
Open Files::
226275
[/user/username/projects/random/random.ts] *new*
227276
/user/username/projects/random/tsconfig.json (default)
228277
Config::
229278
[/user/username/projects/myproject/dependency/tsconfig.json] *deleted*
279+
[/user/username/projects/myproject/main/tsconfig.json] *modified*
280+
RetainingProjects: *modified*
281+
/user/username/projects/myproject/main/tsconfig.json *deleted*
282+
/user/username/projects/myproject/tsconfig.json *deleted*
283+
RetainingOpenFiles:
284+
/user/username/projects/myproject/main/main.ts
285+
[/user/username/projects/myproject/tsconfig.json] *deleted*
230286
[/user/username/projects/random/tsconfig.json]
231287
RetainingProjects:
232288
/user/username/projects/random/tsconfig.json

0 commit comments

Comments
 (0)