Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 26 additions & 16 deletions src/server/session.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,7 @@ namespace ts.server {
// correct results to all other projects.

const defaultProjectResults = perProjectResults.get(defaultProject);
if (defaultProjectResults?.[0].references[0]?.isDefinition === undefined) {
if (defaultProjectResults?.[0]?.references[0]?.isDefinition === undefined) {
// Clear all isDefinition properties
perProjectResults.forEach(projectResults => {
for (const referencedSymbol of projectResults) {
Expand Down Expand Up @@ -531,26 +531,35 @@ namespace ts.server {
defaultDefinition :
defaultProject.getLanguageService().getSourceMapper().tryGetSourcePosition(defaultDefinition!));

// Track which projects we have already searched so that we don't repeat searches.
// We store the project key, rather than the project, because that's what `loadAncestorProjectTree` wants.
// (For that same reason, we don't use `resultsMap` for this check.)
const searchedProjects = new Set<string>();
// The keys of resultsMap allow us to check which projects have already been searched, but we also
// maintain a set of strings because that's what `loadAncestorProjectTree` wants.
const searchedProjectKeys = new Set<string>();

onCancellation:
while (queue.length) {
while (queue.length) {
if (cancellationToken.isCancellationRequested()) break onCancellation;

let skipCount = 0;
for (; skipCount < queue.length && resultsMap.has(queue[skipCount].project); skipCount++);
Comment thread
amcasey marked this conversation as resolved.

if (skipCount === queue.length) {
queue.length = 0;
break;
}

if (skipCount > 0) {
queue.splice(0, skipCount);
}

// NB: we may still skip if it's a project reference redirect
const { project, location } = queue.shift()!;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make more sense long-term not to de-queue at all? Just iterate through and toss the array at the end?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess not, then it would just get longer and longer.


if (isLocationProjectReferenceRedirect(project, location)) continue;

if (!tryAddToSet(searchedProjects, getProjectKey(project))) continue;

const projectResults = searchPosition(project, location);
if (projectResults) {
resultsMap.set(project, projectResults);
}
resultsMap.set(project, projectResults ?? emptyArray);
searchedProjectKeys.add(getProjectKey(project));
}

// At this point, we know about all projects passed in as arguments and any projects in which
Expand All @@ -559,10 +568,10 @@ namespace ts.server {
// containing `initialLocation`.
if (defaultDefinition) {
// This seems to mean "load all projects downstream from any member of `seenProjects`".
projectService.loadAncestorProjectTree(searchedProjects);
projectService.loadAncestorProjectTree(searchedProjectKeys);
projectService.forEachEnabledProject(project => {
if (cancellationToken.isCancellationRequested()) return; // There's no mechanism for skipping the remaining projects
if (searchedProjects.has(getProjectKey(project))) return; // Can loop forever without this (enqueue here, dequeue above, repeat)
if (resultsMap.has(project)) return; // Can loop forever without this (enqueue here, dequeue above, repeat)
const location = mapDefinitionInProject(defaultDefinition, project, getGeneratedDefinition, getSourceDefinition);
if (location) {