Apply disableReferencedProjectLoad to getOriginalLocationEnsuringConfiguredProject (#44836)

* Apply disableReferencedProjectLoad to getOriginalLocationEnsuringConfiguredProject

* Reuse previously computed values and refine comments

* Add baselines for test matrix
This commit is contained in:
Andrew Casey
2021-07-06 15:22:48 -07:00
committed by GitHub
parent bb7de99e5a
commit 4d5978d1db
18 changed files with 1841 additions and 4 deletions

View File

@@ -3224,20 +3224,39 @@ namespace ts.server {
/*@internal*/
getOriginalLocationEnsuringConfiguredProject(project: Project, location: DocumentPosition): DocumentPosition | undefined {
const originalLocation = project.isSourceOfProjectReferenceRedirect(location.fileName) ?
const isSourceOfProjectReferenceRedirect = project.isSourceOfProjectReferenceRedirect(location.fileName);
const originalLocation = isSourceOfProjectReferenceRedirect ?
location :
project.getSourceMapper().tryGetSourcePosition(location);
if (!originalLocation) return undefined;
const { fileName } = originalLocation;
if (!this.getScriptInfo(fileName) && !this.host.fileExists(fileName)) return undefined;
const scriptInfo = this.getScriptInfo(fileName);
if (!scriptInfo && !this.host.fileExists(fileName)) return undefined;
const originalFileInfo: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) };
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
if (!configFileName) return undefined;
let configuredProject: ConfiguredProject | undefined = this.findConfiguredProjectByProjectName(configFileName) ||
this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`);
let configuredProject: ConfiguredProject | undefined = this.findConfiguredProjectByProjectName(configFileName);
if (!configuredProject) {
if (project.getCompilerOptions().disableReferencedProjectLoad) {
// If location was a project reference redirect, then `location` and `originalLocation` are the same.
if (isSourceOfProjectReferenceRedirect) {
return location;
}
// Otherwise, if we found `originalLocation` via a source map instead, then we check whether it's in
// an open project. If it is, we should search the containing project(s), even though the "default"
// configured project isn't open. However, if it's not in an open project, we need to stick with
// `location` (i.e. the .d.ts file) because otherwise we'll miss the references in that file.
return scriptInfo?.containingProjects.length
? originalLocation
: location;
}
configuredProject = this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName}${location !== originalLocation ? " for location: " + location.fileName : ""}`);
}
updateProjectIfDirty(configuredProject);
const projectContainsOriginalInfo = (project: ConfiguredProject) => {

View File

@@ -1353,5 +1353,120 @@ bar;`
});
baselineTsserverLogs("projectReferences", `when files from two projects are open and one project references`, session);
});
describe("find refs to symbol from other project", () => {
const indexA: File = {
path: `${tscWatch.projectRoot}/a/index.ts`,
content: `import { B } from "../b/lib";
const b: B = new B();`
};
const configB: File = {
path: `${tscWatch.projectRoot}/b/tsconfig.json`,
content: `{
"compilerOptions": {
"declarationMap": true,
"outDir": "lib",
"composite": true
}
}`
};
const indexB: File = {
path: `${tscWatch.projectRoot}/b/index.ts`,
content: `export class B {
M() {}
}`
};
const helperB: File = {
path: `${tscWatch.projectRoot}/b/helper.ts`,
content: `import { B } from ".";
const b: B = new B();`
};
const dtsB: File = {
path: `${tscWatch.projectRoot}/b/lib/index.d.ts`,
content: `export declare class B {
M(): void;
}
//# sourceMappingURL=index.d.ts.map`
};
const dtsMapB: File = {
path: `${tscWatch.projectRoot}/b/lib/index.d.ts.map`,
content: `{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,qBAAa,CAAC;IACV,CAAC;CACJ"}`
};
function baselineDisableReferencedProjectLoad(
projectAlreadyLoaded: boolean,
disableReferencedProjectLoad: boolean,
disableSourceOfProjectReferenceRedirect: boolean,
dtsMapPresent: boolean) {
// Mangled to stay under windows path length limit
const subScenario =
`when proj ${projectAlreadyLoaded ? "is" : "is not"} loaded ` +
` and refd proj loading is ${disableReferencedProjectLoad ? "disabled" : "enabled"}` +
` and proj ref redirects are ${disableSourceOfProjectReferenceRedirect ? "disabled" : "enabled"}` +
` and a decl map is ${dtsMapPresent ? "present" : "missing"}`;
const compilerOptions: CompilerOptions = {
disableReferencedProjectLoad,
disableSourceOfProjectReferenceRedirect,
composite: true
};
it(subScenario, () => {
const configA: File = {
path: `${tscWatch.projectRoot}/a/tsconfig.json`,
content: `{
"compilerOptions": ${JSON.stringify(compilerOptions)},
"references": [{ "path": "../b" }]
}`
};
const host = createServerHost([configA, indexA, configB, indexB, helperB, dtsB, ...(dtsMapPresent ? [dtsMapB] : [])]);
const session = createSession(host, { logger: createLoggerWithInMemoryLogs() });
openFilesForSession([indexA, ...(projectAlreadyLoaded ? [helperB] : [])], session);
session.executeCommandSeq<protocol.ReferencesRequest>({
command: protocol.CommandTypes.References,
arguments: protocolFileLocationFromSubstring(indexA, `B`, { index: 1 })
});
baselineTsserverLogs("projectReferences", `find all references to a symbol declared in another project ${subScenario}`, session);
});
}
/* eslint-disable boolean-trivia */
// Pre-loaded = A file from project B is already open when FAR is invoked
// dRPL = Project A has disableReferencedProjectLoad
// dSOPRR = Project A has disableSourceOfProjectReferenceRedirect
// Map = The declaration map file b/lib/index.d.ts.map exists
// B refs = files under directory b in which references are found (all scenarios find all references in a/index.ts)
// Pre-loaded | dRPL | dSOPRR | Map | B state | Notes | B refs | Notes
// -----------+--------+--------+----------+------------+--------------+---------------------+---------------------------------------------------
baselineDisableReferencedProjectLoad(true, true, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project
baselineDisableReferencedProjectLoad(true, true, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded
baselineDisableReferencedProjectLoad(true, true, false, true); // Pre-loaded | | index.ts, helper.ts |
baselineDisableReferencedProjectLoad(true, true, false, false); // Pre-loaded | | index.ts, helper.ts |
baselineDisableReferencedProjectLoad(true, false, true, true); // Pre-loaded | | index.ts, helper.ts | Via map and pre-loaded project
baselineDisableReferencedProjectLoad(true, false, true, false); // Pre-loaded | | lib/index.d.ts | Even though project is loaded
baselineDisableReferencedProjectLoad(true, false, false, true); // Pre-loaded | | index.ts, helper.ts |
baselineDisableReferencedProjectLoad(true, false, false, false); // Pre-loaded | | index.ts, helper.ts |
baselineDisableReferencedProjectLoad(false, true, true, true); // Not loaded | | lib/index.d.ts | Even though map is present
baselineDisableReferencedProjectLoad(false, true, true, false); // Not loaded | | lib/index.d.ts |
baselineDisableReferencedProjectLoad(false, true, false, true); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a
baselineDisableReferencedProjectLoad(false, true, false, false); // Not loaded | | index.ts | But not helper.ts, which is not referenced from a
baselineDisableReferencedProjectLoad(false, false, true, true); // Loaded | Via map | index.ts, helper.ts | Via map and newly loaded project
baselineDisableReferencedProjectLoad(false, false, true, false); // Not loaded | | lib/index.d.ts |
baselineDisableReferencedProjectLoad(false, false, false, true); // Loaded | Via redirect | index.ts, helper.ts |
baselineDisableReferencedProjectLoad(false, false, false, false); // Loaded | Via redirect | index.ts, helper.ts |
/* eslint-enable boolean-trivia */
});
});
}