Merge pull request #26173 from Microsoft/compositeProjectGoToDefinition

Fixes to ensure getDefinitionAndBoundSpan works correctly when using composite projects
This commit is contained in:
Sheetal Nandi 2018-08-03 10:35:32 -07:00 committed by GitHub
commit b1878e62bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 6 deletions

View File

@ -2358,7 +2358,7 @@ namespace ts {
if (sourceFile === undefined) {
return undefined;
}
sourceFile.path = toPath(refPath);
const commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
return { commandLine, sourceFile };
}

View File

@ -100,7 +100,8 @@ namespace ts.sourcemaps {
// Lookup file in program, if provided
const path = toPath(fileName, location, host.getCanonicalFileName);
const file = program && program.getSourceFile(path);
if (!file) {
// file returned here could be .d.ts when asked for .ts file if projectReferences and module resolution created this source file
if (!file || file.resolvedPath !== path) {
// Otherwise check the cache (which may hit disk)
return fallbackCache.get(path);
}
@ -373,4 +374,4 @@ namespace ts.sourcemaps {
encodedText.charCodeAt(pos) === CharacterCodes.comma ||
encodedText.charCodeAt(pos) === CharacterCodes.semicolon);
}
}
}

View File

@ -2243,6 +2243,20 @@ namespace ts.server {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
markOriginalProjectsAsUsed(project);
}
else {
// If the configured project for project reference has more than zero references, keep it alive
const resolvedProjectReferences = project.getResolvedProjectReferences();
if (resolvedProjectReferences) {
for (const ref of resolvedProjectReferences) {
if (ref) {
const refProject = this.configuredProjects.get(ref.sourceFile.path);
if (refProject && refProject.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
}
}
}
}
}
});
// Remove all the non marked projects

View File

@ -572,6 +572,14 @@ namespace ts.server {
for (const f of this.program.getSourceFiles()) {
this.detachScriptInfoIfNotRoot(f.fileName);
}
const projectReferences = this.program.getProjectReferences();
if (projectReferences) {
for (const ref of projectReferences) {
if (ref) {
this.detachScriptInfoFromProject(ref.sourceFile.fileName);
}
}
}
}
// Release external files
forEach(this.externalFiles, externalFile => this.detachScriptInfoIfNotRoot(externalFile));
@ -1367,6 +1375,12 @@ namespace ts.server {
this.projectReferences = refs;
}
/*@internal*/
getResolvedProjectReferences() {
const program = this.getCurrentProgram();
return program && program.getProjectReferences();
}
enablePlugins() {
const host = this.projectService.host;
const options = this.getCompilationSettings();

View File

@ -9183,8 +9183,21 @@ export function Test2() {
content: 'import { fnA, instanceA } from "../a/bin/a";\nimport { fnB } from "../b/bin/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
};
function makeSampleProjects() {
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, userTs, dummyFile]);
const userTsForConfigProject: File = {
path: "/user/user.ts",
content: 'import { fnA, instanceA } from "../a/a";\nimport { fnB } from "../b/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
};
const userTsconfig: File = {
path: "/user/tsconfig.json",
content: JSON.stringify({
file: ["user.ts"],
references: [{ path: "../a" }, { path: "../b" }]
})
};
function makeSampleProjects(addUserTsConfig?: boolean) {
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, ...(addUserTsConfig ? [userTsForConfigProject, userTsconfig] : [userTs]), dummyFile]);
const session = createSession(host);
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
@ -9195,7 +9208,7 @@ export function Test2() {
openFilesForSession([userTs], session);
const service = session.getProjectService();
checkNumberOfProjects(service, { inferredProjects: 1 });
checkNumberOfProjects(service, addUserTsConfig ? { configuredProjects: 1 } : { inferredProjects: 1 });
return session;
}
@ -9247,6 +9260,10 @@ export function Test2() {
verifyATsConfigProject(session); // ATsConfig should still be alive
}
function verifyUserTsConfigProject(session: TestSession) {
checkProjectActualFiles(session.getProjectService().configuredProjects.get(userTsconfig.path)!, [userTs.path, aDts.path, userTsconfig.path]);
}
it("goToDefinition", () => {
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
@ -9264,6 +9281,29 @@ export function Test2() {
verifySingleInferredProject(session);
});
it("getDefinitionAndBoundSpan with file navigation", () => {
const session = makeSampleProjects(/*addUserTsConfig*/ true);
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, {
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
});
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 1 }); debugger;
verifyUserTsConfigProject(session);
// Navigate to the definition
closeFilesForSession([userTs], session);
openFilesForSession([aTs], session);
// UserTs configured project should be alive
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 });
verifyUserTsConfigProject(session);
verifyATsConfigProject(session);
closeFilesForSession([aTs], session);
verifyOnlyOrphanInferredProject(session);
});
it("goToType", () => {
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.TypeDefinitionRequest, protocol.TypeDefinitionResponse>(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));