Skip to content

Commit c937666

Browse files
committed
Revert "Revert of Search ancestor and its references for default projects #57196 (#59634)"
1 parent 0228b37 commit c937666

File tree

121 files changed

+8465
-3895
lines changed

Some content is hidden

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

121 files changed

+8465
-3895
lines changed

src/server/editorServices.ts

Lines changed: 99 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
DocumentRegistry,
3232
DocumentRegistryBucketKeyWithMode,
3333
emptyOptions,
34+
endsWith,
3435
ensureTrailingDirectorySeparator,
3536
equateStringsCaseInsensitive,
3637
equateStringsCaseSensitive,
@@ -643,10 +644,37 @@ export interface ProjectServiceOptions {
643644
*/
644645
export type ConfigFileName = NormalizedPath | false;
645646

647+
/**
648+
* Stores cached config file name for info as well as ancestor so is a map
649+
* Key is false for Open ScriptInfo
650+
* Key is NormalizedPath for Config file name
651+
* @internal
652+
*/
653+
export type ConfigFileMapForOpenFile = Map<ConfigFileName, ConfigFileName>;
654+
655+
/**
656+
* The cache for open script info will have
657+
* ConfigFileName or false if ancestors are not looked up
658+
* Map if ancestors are looked up
659+
* @internal
660+
*/
661+
export type ConfigFileForOpenFile = ConfigFileName | ConfigFileMapForOpenFile;
662+
646663
/** Gets cached value of config file name based on open script info or ancestor script info */
647-
function getConfigFileNameFromCache(info: OpenScriptInfoOrClosedOrConfigFileInfo, cache: Map<Path, ConfigFileName> | undefined): ConfigFileName | undefined {
648-
if (!cache || isAncestorConfigFileInfo(info)) return undefined;
649-
return cache.get(info.path);
664+
function getConfigFileNameFromCache(info: OpenScriptInfoOrClosedOrConfigFileInfo, cache: Map<Path, ConfigFileForOpenFile> | undefined): ConfigFileName | undefined {
665+
if (!cache) return undefined;
666+
const configFileForOpenFile = cache.get(info.path);
667+
if (configFileForOpenFile === undefined) return undefined;
668+
if (!isAncestorConfigFileInfo(info)) {
669+
return isString(configFileForOpenFile) || !configFileForOpenFile ?
670+
configFileForOpenFile : // direct result
671+
configFileForOpenFile.get(/*key*/ false); // Its a map, use false as the key for the info's config file name
672+
}
673+
else {
674+
return configFileForOpenFile && !isString(configFileForOpenFile) ? // Map with fileName as key
675+
configFileForOpenFile.get(info.fileName) :
676+
undefined; // No result for the config file name
677+
}
650678
}
651679

652680
/** @internal */
@@ -661,6 +689,7 @@ export interface AncestorConfigFileInfo {
661689
/** path of open file so we can look at correct root */
662690
path: Path;
663691
configFileInfo: true;
692+
isForDefaultProject: boolean;
664693
}
665694
/** @internal */
666695
export type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo;
@@ -709,6 +738,8 @@ function forEachAncestorProject<T>(
709738
allowDeferredClosed: boolean | undefined,
710739
/** Used with ConfiguredProjectLoadKind.Reload to check if this project was already reloaded */
711740
reloadedProjects: Set<ConfiguredProject> | undefined,
741+
/** true means we are looking for solution, so we can stop if found project is not composite to go into parent solution */
742+
searchOnlyPotentialSolution: boolean,
712743
/** Used with ConfiguredProjectLoadKind.Reload to specify delay reload, and also a set of configured projects already marked for delay load */
713744
delayReloadedConfiguredProjects?: Set<ConfiguredProject>,
714745
): T | undefined {
@@ -718,7 +749,10 @@ function forEachAncestorProject<T>(
718749
if (
719750
!project.initialLoadPending &&
720751
(
721-
!project.getCompilerOptions().composite ||
752+
(searchOnlyPotentialSolution && !project.getCompilerOptions().composite) ||
753+
// Currently disableSolutionSearching is shared for finding solution/project when
754+
// - loading solution for find all references
755+
// - trying to find default project
722756
project.getCompilerOptions().disableSolutionSearching
723757
)
724758
) return;
@@ -728,6 +762,7 @@ function forEachAncestorProject<T>(
728762
fileName: project.getConfigFilePath(),
729763
path: info.path,
730764
configFileInfo: true,
765+
isForDefaultProject: !searchOnlyPotentialSolution,
731766
}, kind === ConfiguredProjectLoadKind.Find);
732767
if (!configFileName) return;
733768

@@ -737,9 +772,9 @@ function forEachAncestorProject<T>(
737772
kind,
738773
reason,
739774
allowDeferredClosed,
740-
/*triggerFile*/ undefined,
775+
!searchOnlyPotentialSolution ? info.fileName : undefined, // Config Diag event for project if its for default project
741776
reloadedProjects,
742-
/*delayLoad*/ true,
777+
searchOnlyPotentialSolution, // Delay load if we are searching for solution
743778
delayReloadedConfiguredProjects,
744779
);
745780
if (!ancestor) return;
@@ -1219,7 +1254,7 @@ export class ProjectService {
12191254
*/
12201255
readonly openFiles: Map<Path, NormalizedPath | undefined> = new Map<Path, NormalizedPath | undefined>();
12211256
/** Config files looked up and cached config files for open script info */
1222-
private readonly configFileForOpenFiles = new Map<Path, ConfigFileName>();
1257+
private readonly configFileForOpenFiles = new Map<Path, ConfigFileForOpenFile>();
12231258
/** Set of open script infos that are root of inferred project */
12241259
private rootOfInferredProjects = new Set<ScriptInfo>();
12251260
/**
@@ -1258,7 +1293,7 @@ export class ProjectService {
12581293
* All the open script info that needs recalculation of the default project,
12591294
* this also caches config file info before config file change was detected to use it in case projects are not updated yet
12601295
*/
1261-
private pendingOpenFileProjectUpdates?: Map<Path, ConfigFileName>;
1296+
private pendingOpenFileProjectUpdates?: Map<Path, ConfigFileForOpenFile>;
12621297
/** @internal */
12631298
pendingEnsureProjectForOpenFiles = false;
12641299

@@ -2277,7 +2312,7 @@ export class ProjectService {
22772312
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
22782313

22792314
let openFilesImpactedByConfigFile: Set<Path> | undefined;
2280-
if (this.openFiles.has(info.path) && !isAncestorConfigFileInfo(info)) {
2315+
if (this.openFiles.has(info.path) && (!isAncestorConfigFileInfo(info) || info.isForDefaultProject)) {
22812316
// By default the info would get impacted by presence of config file since its in the detection path
22822317
// Only adding the info as a root to inferred project will need the existence to be watched by file watcher
22832318
if (configFileExistenceInfo) (configFileExistenceInfo.openFilesImpactedByConfigFile ??= new Set()).add(info.path);
@@ -2470,31 +2505,39 @@ export class ProjectService {
24702505

24712506
// If projectRootPath doesn't contain info.path, then do normal search for config file
24722507
const anySearchPathOk = !projectRootPath || !isSearchPathInProjectRoot();
2473-
// For ancestor of config file always ignore its own directory since its going to result in itself
2474-
let searchInDirectory = !isAncestorConfigFileInfo(info);
2508+
2509+
let searchTsconfig = true;
2510+
let searchJsconfig = true;
2511+
if (isAncestorConfigFileInfo(info)) {
2512+
// For ancestor of config file always ignore itself
2513+
if (endsWith(info.fileName, "tsconfig.json")) searchTsconfig = false;
2514+
else searchTsconfig = searchJsconfig = false;
2515+
}
24752516
do {
2476-
if (searchInDirectory) {
2477-
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
2517+
const canonicalSearchPath = normalizedPathToPath(searchPath, this.currentDirectory, this.toCanonicalFileName);
2518+
if (searchTsconfig) {
24782519
const tsconfigFileName = asNormalizedPath(combinePaths(searchPath, "tsconfig.json"));
2479-
let result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName);
2520+
const result = action(combinePaths(canonicalSearchPath, "tsconfig.json") as NormalizedPath, tsconfigFileName);
24802521
if (result) return tsconfigFileName;
2522+
}
24812523

2524+
if (searchJsconfig) {
24822525
const jsconfigFileName = asNormalizedPath(combinePaths(searchPath, "jsconfig.json"));
2483-
result = action(combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, jsconfigFileName);
2526+
const result = action(combinePaths(canonicalSearchPath, "jsconfig.json") as NormalizedPath, jsconfigFileName);
24842527
if (result) return jsconfigFileName;
2528+
}
24852529

2486-
// If we started within node_modules, don't look outside node_modules.
2487-
// Otherwise, we might pick up a very large project and pull in the world,
2488-
// causing an editor delay.
2489-
if (isNodeModulesDirectory(canonicalSearchPath)) {
2490-
break;
2491-
}
2530+
// If we started within node_modules, don't look outside node_modules.
2531+
// Otherwise, we might pick up a very large project and pull in the world,
2532+
// causing an editor delay.
2533+
if (isNodeModulesDirectory(canonicalSearchPath)) {
2534+
break;
24922535
}
24932536

24942537
const parentPath = asNormalizedPath(getDirectoryPath(searchPath));
24952538
if (parentPath === searchPath) break;
24962539
searchPath = parentPath;
2497-
searchInDirectory = true;
2540+
searchTsconfig = searchJsconfig = true;
24982541
}
24992542
while (anySearchPathOk || isSearchPathInProjectRoot());
25002543

@@ -2529,8 +2572,24 @@ export class ProjectService {
25292572
configFileName: NormalizedPath | undefined,
25302573
) {
25312574
if (!this.openFiles.has(info.path)) return; // Dont cache for closed script infos
2532-
if (isAncestorConfigFileInfo(info)) return; // Dont cache for ancestors
2533-
this.configFileForOpenFiles.set(info.path, configFileName || false);
2575+
const config = configFileName || false;
2576+
if (!isAncestorConfigFileInfo(info)) {
2577+
// Set value for open script info
2578+
this.configFileForOpenFiles.set(info.path, config);
2579+
}
2580+
else {
2581+
// Need to set value for ancestor in ConfigFileMapForOpenFile
2582+
let configFileForOpenFile = this.configFileForOpenFiles.get(info.path)!;
2583+
if (!configFileForOpenFile || isString(configFileForOpenFile)) {
2584+
// We have value for open script info in cache, make a map with that as false key and set new vlaue
2585+
this.configFileForOpenFiles.set(
2586+
info.path,
2587+
configFileForOpenFile = new Map().set(false, configFileForOpenFile),
2588+
);
2589+
}
2590+
// Set value of for ancestor in the map
2591+
configFileForOpenFile.set(info.fileName, config);
2592+
}
25342593
}
25352594

25362595
/**
@@ -4275,7 +4334,8 @@ export class ProjectService {
42754334
function tryFindDefaultConfiguredProject(project: ConfiguredProject): ConfiguredProject | undefined {
42764335
return isDefaultProject(project) ?
42774336
defaultProject :
4278-
tryFindDefaultConfiguredProjectFromReferences(project);
4337+
(tryFindDefaultConfiguredProjectFromReferences(project) ??
4338+
tryFindDefaultConfiguredProjectFromAncestor(project));
42794339
}
42804340

42814341
function isDefaultProject(project: ConfiguredProject): ConfiguredProject | undefined {
@@ -4305,6 +4365,19 @@ export class ProjectService {
43054365
reloadedProjects,
43064366
);
43074367
}
4368+
4369+
function tryFindDefaultConfiguredProjectFromAncestor(project: ConfiguredProject) {
4370+
return forEachAncestorProject( // If not in referenced projects, try ancestors and its references
4371+
info,
4372+
project,
4373+
tryFindDefaultConfiguredProject,
4374+
kind,
4375+
`Creating possible configured project for ${info.fileName} to open`,
4376+
allowDeferredClosed,
4377+
reloadedProjects,
4378+
/*searchOnlyPotentialSolution*/ false,
4379+
);
4380+
}
43084381
}
43094382

43104383
/**
@@ -4349,6 +4422,7 @@ export class ProjectService {
43494422
`Creating project possibly referencing default composite project ${defaultProject.getProjectName()} of open file ${info.fileName}`,
43504423
allowDeferredClosed,
43514424
reloadedProjects,
4425+
/*searchOnlyPotentialSolution*/ true,
43524426
delayReloadedConfiguredProjects,
43534427
);
43544428
}

tests/baselines/reference/tsserver/configuredProjects/Open-ref-of-configured-project-when-open-file-gets-added-to-the-project-as-part-of-configured-file-update-buts-its-open-file-references-are-all-closed-when-the-update-happens.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ Info seq [hh:mm:ss:mss] request:
228228
"type": "request"
229229
}
230230
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/project/a/b/src/file2.ts ProjectRootPath: undefined:: Result: /user/username/projects/project/a/b/tsconfig.json
231+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/project/a/b/tsconfig.json ProjectRootPath: undefined:: Result: undefined
231232
Info seq [hh:mm:ss:mss] event:
232233
{
233234
"seq": 0,

tests/baselines/reference/tsserver/configuredProjects/Open-ref-of-configured-project-when-open-file-gets-added-to-the-project-as-part-of-configured-file-update.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,7 @@ Info seq [hh:mm:ss:mss] request:
228228
"type": "request"
229229
}
230230
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/project/a/b/src/file2.ts ProjectRootPath: undefined:: Result: /user/username/projects/project/a/b/tsconfig.json
231+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/project/a/b/tsconfig.json ProjectRootPath: undefined:: Result: undefined
231232
Info seq [hh:mm:ss:mss] event:
232233
{
233234
"seq": 0,

tests/baselines/reference/tsserver/configuredProjects/add-and-then-remove-a-config-file-in-a-folder-with-loose-files.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
366366
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json
367367
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
368368
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject2*
369+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
369370
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
370371
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 2 projectProgramVersion: 1 structureChanged: true structureIsReused:: Not Elapsed:: *ms
371372
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
@@ -665,6 +666,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
665666
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject1*,/user/username/projects/myproject/tsconfig.json
666667
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
667668
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject2*
669+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
668670
Info seq [hh:mm:ss:mss] Starting updateGraphWorker: Project: /dev/null/inferredProject1*
669671
Info seq [hh:mm:ss:mss] Finishing updateGraphWorker: Project: /dev/null/inferredProject1* projectStateVersion: 4 projectProgramVersion: 3 structureChanged: true structureIsReused:: Not Elapsed:: *ms
670672
Info seq [hh:mm:ss:mss] Project '/dev/null/inferredProject1*' (Inferred)
@@ -1731,6 +1733,7 @@ Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile
17311733
Info seq [hh:mm:ss:mss] Projects: /user/username/projects/myproject/tsconfig.json
17321734
Info seq [hh:mm:ss:mss] FileName: /user/username/projects/myproject/commonFile2.ts ProjectRootPath: undefined
17331735
Info seq [hh:mm:ss:mss] Projects: /dev/null/inferredProject4*
1736+
Info seq [hh:mm:ss:mss] getConfigFileNameForFile:: File: /user/username/projects/myproject/tsconfig.json ProjectRootPath: undefined:: Result: undefined
17341737
Info seq [hh:mm:ss:mss] After ensureProjectForOpenFiles:
17351738
Info seq [hh:mm:ss:mss] Project '/user/username/projects/myproject/tsconfig.json' (Configured)
17361739
Info seq [hh:mm:ss:mss] Files (2)

0 commit comments

Comments
 (0)