Skip to content

Commit dbd6717

Browse files
committed
Load the ancestor projects to find default project for the file
1 parent 8d2b5f4 commit dbd6717

File tree

75 files changed

+1103
-1325
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+1103
-1325
lines changed

src/server/editorServices.ts

Lines changed: 521 additions & 328 deletions
Large diffs are not rendered by default.

src/server/project.ts

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -139,15 +139,12 @@ import {
139139
emptyArray,
140140
Errors,
141141
FileStats,
142-
forEachResolvedProjectReferenceProject,
143142
LogLevel,
144143
ModuleImportResult,
145144
Msg,
146145
NormalizedPath,
147146
PackageJsonWatcher,
148-
projectContainsInfoDirectly,
149147
ProjectOptions,
150-
ProjectReferenceProjectLoadKind,
151148
ProjectService,
152149
ScriptInfo,
153150
ServerHost,
@@ -2185,7 +2182,7 @@ export abstract class Project implements LanguageServiceHost, ModuleResolutionHo
21852182
private isDefaultProjectForOpenFiles(): boolean {
21862183
return !!forEachEntry(
21872184
this.projectService.openFiles,
2188-
(_, fileName) => this.projectService.tryGetDefaultProjectForFile(toNormalizedPath(fileName)) === this,
2185+
(_projectRootPath, path) => this.projectService.tryGetDefaultProjectForFile(this.projectService.getScriptInfoForPath(path)!) === this,
21892186
);
21902187
}
21912188

@@ -2681,9 +2678,6 @@ export class ConfiguredProject extends Project {
26812678
/** @internal */
26822679
canConfigFileJsonReportNoInputFiles = false;
26832680

2684-
/** Ref count to the project when opened from external project */
2685-
private externalProjectRefCount = 0;
2686-
26872681
private projectReferences: readonly ProjectReference[] | undefined;
26882682

26892683
/**
@@ -2778,8 +2772,7 @@ export class ConfiguredProject extends Project {
27782772
case ProgramUpdateLevel.Full:
27792773
this.openFileWatchTriggered.clear();
27802774
const reason = Debug.checkDefined(this.pendingUpdateReason);
2781-
this.pendingUpdateReason = undefined;
2782-
this.projectService.reloadConfiguredProject(this, reason, isInitialLoad, /*clearSemanticCache*/ false);
2775+
this.projectService.reloadConfiguredProject(this, reason, isInitialLoad);
27832776
result = true;
27842777
break;
27852778
default:
@@ -2881,85 +2874,12 @@ export class ConfiguredProject extends Project {
28812874
super.close();
28822875
}
28832876

2884-
/** @internal */
2885-
addExternalProjectReference() {
2886-
this.externalProjectRefCount++;
2887-
}
2888-
2889-
/** @internal */
2890-
deleteExternalProjectReference() {
2891-
this.externalProjectRefCount--;
2892-
}
2893-
28942877
/** @internal */
28952878
isSolution() {
28962879
return this.getRootFilesMap().size === 0 &&
28972880
!this.canConfigFileJsonReportNoInputFiles;
28982881
}
28992882

2900-
/**
2901-
* Find the configured project from the project references in project which contains the info directly
2902-
*
2903-
* @internal
2904-
*/
2905-
getDefaultChildProjectFromProjectWithReferences(info: ScriptInfo) {
2906-
return forEachResolvedProjectReferenceProject(
2907-
this,
2908-
info.path,
2909-
child =>
2910-
projectContainsInfoDirectly(child, info) ?
2911-
child :
2912-
undefined,
2913-
ProjectReferenceProjectLoadKind.Find,
2914-
);
2915-
}
2916-
2917-
/**
2918-
* Returns true if the project is needed by any of the open script info/external project
2919-
*
2920-
* @internal
2921-
*/
2922-
hasOpenRef() {
2923-
if (!!this.externalProjectRefCount) {
2924-
return true;
2925-
}
2926-
2927-
// Closed project doesnt have any reference
2928-
if (this.isClosed()) {
2929-
return false;
2930-
}
2931-
2932-
const configFileExistenceInfo = this.projectService.configFileExistenceInfoCache.get(this.canonicalConfigFilePath)!;
2933-
if (this.projectService.hasPendingProjectUpdate(this)) {
2934-
// If there is pending update for this project,
2935-
// we dont know if this project would be needed by any of the open files impacted by this config file
2936-
// In that case keep the project alive if there are open files impacted by this project
2937-
return !!configFileExistenceInfo.openFilesImpactedByConfigFile?.size;
2938-
}
2939-
2940-
// If there is no pending update for this project,
2941-
// We know exact set of open files that get impacted by this configured project as the files in the project
2942-
// The project is referenced only if open files impacted by this project are present in this project
2943-
return !!configFileExistenceInfo.openFilesImpactedByConfigFile && forEachEntry(
2944-
configFileExistenceInfo.openFilesImpactedByConfigFile,
2945-
(_value, infoPath) => {
2946-
const info = this.projectService.getScriptInfoForPath(infoPath)!;
2947-
return this.containsScriptInfo(info) ||
2948-
!!forEachResolvedProjectReferenceProject(
2949-
this,
2950-
info.path,
2951-
child => child.containsScriptInfo(info),
2952-
ProjectReferenceProjectLoadKind.Find,
2953-
);
2954-
},
2955-
) || false;
2956-
}
2957-
2958-
/** @internal */
2959-
hasExternalProjectRef() {
2960-
return !!this.externalProjectRefCount;
2961-
}
2962-
29632883
getEffectiveTypeRoots() {
29642884
return getEffectiveTypeRoots(this.getCompilationSettings(), this) || [];
29652885
}

src/server/scriptInfo.ts

Lines changed: 8 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@ import {
3838
AbsolutePositionAndLineText,
3939
ConfiguredProject,
4040
Errors,
41-
ExternalProject,
4241
InferredProject,
4342
isBackgroundProject,
4443
isConfiguredProject,
@@ -566,15 +565,14 @@ export class ScriptInfo {
566565
case 0:
567566
return Errors.ThrowNoProject();
568567
case 1:
569-
return ensurePrimaryProjectKind(this.containingProjects[0]);
568+
return isBackgroundProject(this.containingProjects[0]) ? Errors.ThrowNoProject() : this.containingProjects[0];
570569
default:
571570
// If this file belongs to multiple projects, below is the order in which default project is used
571+
// - first external project
572572
// - for open script info, its default configured project during opening is default if info is part of it
573573
// - first configured project of which script info is not a source of project reference redirect
574574
// - first configured project
575-
// - first external project
576575
// - first inferred project
577-
let firstExternalProject: ExternalProject | undefined;
578576
let firstConfiguredProject: ConfiguredProject | undefined;
579577
let firstInferredProject: InferredProject | undefined;
580578
let firstNonSourceOfProjectReferenceRedirect: ConfiguredProject | undefined;
@@ -596,20 +594,17 @@ export class ScriptInfo {
596594
}
597595
if (!firstConfiguredProject) firstConfiguredProject = project;
598596
}
599-
else if (!firstExternalProject && isExternalProject(project)) {
600-
firstExternalProject = project;
597+
else if (isExternalProject(project)) {
598+
return project;
601599
}
602600
else if (!firstInferredProject && isInferredProject(project)) {
603601
firstInferredProject = project;
604602
}
605603
}
606-
return ensurePrimaryProjectKind(
607-
defaultConfiguredProject ||
608-
firstNonSourceOfProjectReferenceRedirect ||
609-
firstConfiguredProject ||
610-
firstExternalProject ||
611-
firstInferredProject,
612-
);
604+
return (defaultConfiguredProject ||
605+
firstNonSourceOfProjectReferenceRedirect ||
606+
firstConfiguredProject ||
607+
firstInferredProject) ?? Errors.ThrowNoProject();
613608
}
614609
}
615610

@@ -724,18 +719,6 @@ export class ScriptInfo {
724719
}
725720
}
726721

727-
/**
728-
* Throws an error if `project` is an AutoImportProvider or AuxiliaryProject,
729-
* which are used in the background by other Projects and should never be
730-
* reported as the default project for a ScriptInfo.
731-
*/
732-
function ensurePrimaryProjectKind(project: Project | undefined) {
733-
if (!project || isBackgroundProject(project)) {
734-
return Errors.ThrowNoProject();
735-
}
736-
return project;
737-
}
738-
739722
function failIfInvalidPosition(position: number) {
740723
Debug.assert(typeof position === "number", `Expected position ${position} to be a number.`);
741724
Debug.assert(position >= 0, `Expected position to be non-negative.`);

src/server/session.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,7 +3190,7 @@ export class Session<TMessage = string> implements EventSender {
31903190
return this.requiredResponse(response);
31913191
},
31923192
[protocol.CommandTypes.OpenExternalProject]: (request: protocol.OpenExternalProjectRequest) => {
3193-
this.projectService.openExternalProject(request.arguments, /*print*/ true);
3193+
this.projectService.openExternalProject(request.arguments, /*cleanupAfter*/ true);
31943194
// TODO: GH#20447 report errors
31953195
return this.requiredResponse(/*response*/ true);
31963196
},
@@ -3200,7 +3200,7 @@ export class Session<TMessage = string> implements EventSender {
32003200
return this.requiredResponse(/*response*/ true);
32013201
},
32023202
[protocol.CommandTypes.CloseExternalProject]: (request: protocol.CloseExternalProjectRequest) => {
3203-
this.projectService.closeExternalProject(request.arguments.projectFileName, /*print*/ true);
3203+
this.projectService.closeExternalProject(request.arguments.projectFileName, /*cleanupAfter*/ true);
32043204
// TODO: GH#20447 report errors
32053205
return this.requiredResponse(/*response*/ true);
32063206
},

src/testRunner/unittests/helpers/tsserver.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -495,5 +495,10 @@ export function logInferredProjectsOrphanStatus(session: TestSession) {
495495
}
496496

497497
export function logConfiguredProjectsHasOpenRefStatus(session: TestSession) {
498-
session.getProjectService().configuredProjects.forEach(configuredProject => session.logger.log(`Configured project: ${configuredProject.projectName} hasOpenRef:: ${configuredProject.hasOpenRef()} isClosed: ${configuredProject.isClosed()}`));
498+
const toRemoveConfiguredProjects = session.getProjectService().getOrphanConfiguredProjects(
499+
/*toRetainConfiguredProjects*/ undefined,
500+
/*openFilesWithRetainedConfiguredProject*/ undefined,
501+
/*externalProjectsRetainingConfiguredProjects*/ undefined,
502+
);
503+
session.getProjectService().configuredProjects.forEach(configuredProject => session.logger.log(`Configured project: ${configuredProject.projectName} hasOpenRef:: ${!toRemoveConfiguredProjects.has(configuredProject)} isClosed: ${configuredProject.isClosed()}`));
499504
}

src/testRunner/unittests/tsserver/projects.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ describe("unittests:: tsserver:: projects::", () => {
185185
};
186186
session.host.baselineHost("Before request");
187187
session.logger.info(`request:${ts.server.stringifyIndented(request)}`);
188-
session.getProjectService().openExternalProject(request.arguments, /*print*/ true);
188+
session.getProjectService().openExternalProject(request.arguments, /*cleanupAfter*/ true);
189189
session.host.baselineHost("After request");
190190
baselineTsserverLogs("projects", "external project including config file", session);
191191
});

tests/baselines/reference/api/typescript.d.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3476,8 +3476,6 @@ declare namespace ts {
34763476
*/
34773477
class ConfiguredProject extends Project {
34783478
readonly canonicalConfigFilePath: NormalizedPath;
3479-
/** Ref count to the project when opened from external project */
3480-
private externalProjectRefCount;
34813479
private projectReferences;
34823480
/**
34833481
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
@@ -3704,7 +3702,7 @@ declare namespace ts {
37043702
/**
37053703
* maps external project file name to list of config files that were the part of this project
37063704
*/
3707-
private readonly externalProjectToConfiguredProjectMap;
3705+
private readonly externalProjectToConfigFilesMap;
37083706
/**
37093707
* external projects (configuration and list of root files is not controlled by tsserver)
37103708
*/
@@ -3720,7 +3718,7 @@ declare namespace ts {
37203718
/**
37213719
* Open files: with value being project root path, and key being Path of the file that is open
37223720
*/
3723-
readonly openFiles: Map<string, NormalizedPath | undefined>;
3721+
readonly openFiles: Map<Path, NormalizedPath | undefined>;
37243722
/**
37253723
* Map of open files that are opened without complete path but have projectRoot as current directory
37263724
*/
@@ -3815,6 +3813,8 @@ declare namespace ts {
38153813
* the newly opened file.
38163814
*/
38173815
private forEachConfigFileLocation;
3816+
private getConfigFileNameForFileFromCache;
3817+
private setConfigFileNameForFileInCache;
38183818
/**
38193819
* This function tries to search for a tsconfig.json for the given file.
38203820
* This is different from the method the compiler uses because
@@ -3868,14 +3868,6 @@ declare namespace ts {
38683868
* This does not reload contents of open files from disk. But we could do that if needed
38693869
*/
38703870
reloadProjects(): void;
3871-
/**
3872-
* This function goes through all the openFiles and tries to file the config file for them.
3873-
* If the config file is found and it refers to existing project, it reloads it either immediately
3874-
* or schedules it for reload depending on delayReload option
3875-
* If there is no existing project it just opens the configured project for the config file
3876-
* reloadForInfo provides a way to filter out files to reload configured project for
3877-
*/
3878-
private reloadConfiguredProjectForFiles;
38793871
/**
38803872
* Remove the root of inferred project if script info is part of another project
38813873
*/
@@ -3896,12 +3888,13 @@ declare namespace ts {
38963888
openClientFile(fileName: string, fileContent?: string, scriptKind?: ScriptKind, projectRootPath?: string): OpenConfiguredProjectResult;
38973889
private findExternalProjectContainingOpenScriptInfo;
38983890
private getOrCreateOpenScriptInfo;
3891+
private tryFindDefaultConfiguredProjectForOpenScriptInfo;
38993892
private assignProjectToOpenedScriptInfo;
3900-
private createAncestorProjects;
3893+
private forEachAncestorProject;
39013894
private ensureProjectChildren;
3902-
private cleanupAfterOpeningFile;
3895+
private cleanupConfiguredProjects;
3896+
private cleanupProjectsAndScriptInfos;
39033897
openClientFileWithNormalizedPath(fileName: NormalizedPath, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, projectRootPath?: NormalizedPath): OpenConfiguredProjectResult;
3904-
private removeOrphanConfiguredProjects;
39053898
private removeOrphanScriptInfos;
39063899
private telemetryOnOpenFile;
39073900
/**
@@ -3910,7 +3903,6 @@ declare namespace ts {
39103903
*/
39113904
closeClientFile(uncheckedFileName: string): void;
39123905
private collectChanges;
3913-
private closeConfiguredProjectReferencedFromExternalProject;
39143906
closeExternalProject(uncheckedFileName: string): void;
39153907
openExternalProjects(projects: protocol.ExternalProject[]): void;
39163908
/** Makes a filename safe to insert in a RegExp */

tests/baselines/reference/tsserver/autoImportProvider/Does-not-create-auto-import-providers-upon-opening-projects-for-find-all-references.js

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -517,19 +517,11 @@ Info seq [hh:mm:ss:mss] event:
517517
}
518518
}
519519
Info seq [hh:mm:ss:mss] Finding references to /packages/b/index.ts position 13 in project /tsconfig.json
520-
Info seq [hh:mm:ss:mss] Search path: /packages/b
521-
Info seq [hh:mm:ss:mss] For info: /packages/b/index.ts :: Config file name: /packages/b/tsconfig.json
522-
Info seq [hh:mm:ss:mss] Search path: /packages/b
523-
Info seq [hh:mm:ss:mss] For info: /packages/b/index.ts :: Config file name: /packages/b/tsconfig.json
524520
Info seq [hh:mm:ss:mss] Search path: /packages/a
525521
Info seq [hh:mm:ss:mss] For info: /packages/a/index.ts :: Config file name: /packages/a/tsconfig.json
526522
Info seq [hh:mm:ss:mss] Search path: /packages/a
527523
Info seq [hh:mm:ss:mss] For info: /packages/a/index.ts :: Config file name: /packages/a/tsconfig.json
528524
Info seq [hh:mm:ss:mss] Finding references to /packages/b/index.ts position 13 in project /packages/a/tsconfig.json
529-
Info seq [hh:mm:ss:mss] Search path: /packages/b
530-
Info seq [hh:mm:ss:mss] For info: /packages/b/index.ts :: Config file name: /packages/b/tsconfig.json
531-
Info seq [hh:mm:ss:mss] Search path: /packages/b
532-
Info seq [hh:mm:ss:mss] For info: /packages/b/index.ts :: Config file name: /packages/b/tsconfig.json
533525
Info seq [hh:mm:ss:mss] response:
534526
{
535527
"response": {

tests/baselines/reference/tsserver/declarationFileMaps/findAllReferences-starting-at-definition.js

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -857,10 +857,6 @@ Info seq [hh:mm:ss:mss] request:
857857
Info seq [hh:mm:ss:mss] Finding references to /a/a.ts position 16 in project /a/tsconfig.json
858858
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/bin/a.d.ts.map 500 undefined WatchType: Closed Script info
859859
Info seq [hh:mm:ss:mss] Finding references to /a/bin/a.d.ts position 24 in project /dev/null/inferredProject1*
860-
Info seq [hh:mm:ss:mss] Search path: /a
861-
Info seq [hh:mm:ss:mss] For info: /a/a.ts :: Config file name: /a/tsconfig.json
862-
Info seq [hh:mm:ss:mss] Search path: /a
863-
Info seq [hh:mm:ss:mss] For info: /a/a.ts :: Config file name: /a/tsconfig.json
864860
Info seq [hh:mm:ss:mss] response:
865861
{
866862
"response": {

tests/baselines/reference/tsserver/declarationFileMaps/renameLocations-starting-at-definition.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -855,8 +855,6 @@ Info seq [hh:mm:ss:mss] request:
855855
"type": "request"
856856
}
857857
Info seq [hh:mm:ss:mss] FileWatcher:: Added:: WatchInfo: /a/bin/a.d.ts.map 500 undefined WatchType: Closed Script info
858-
Info seq [hh:mm:ss:mss] Search path: /a
859-
Info seq [hh:mm:ss:mss] For info: /a/a.ts :: Config file name: /a/tsconfig.json
860858
Info seq [hh:mm:ss:mss] response:
861859
{
862860
"response": {

0 commit comments

Comments
 (0)