Skip to content

Commit 15af7e1

Browse files
authored
Merge pull request microsoft#28400 from Microsoft/gotoDefinition
Fix the issue with file being included in the referencing project on rename when it wasnt included earlier
2 parents 16ea9af + 3ec0603 commit 15af7e1

File tree

3 files changed

+142
-75
lines changed

3 files changed

+142
-75
lines changed

src/compiler/sourcemapDecoder.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ namespace ts.sourcemaps {
8383
if (!maps[targetIndex] || comparePaths(loc.fileName, maps[targetIndex].sourcePath, sourceRoot, !host.useCaseSensitiveFileNames) !== 0) {
8484
return loc;
8585
}
86-
return { fileName: toPath(map.file!, sourceRoot, host.getCanonicalFileName), position: maps[targetIndex].emittedPosition }; // Closest pos
86+
return { fileName: getNormalizedAbsolutePath(map.file!, sourceRoot), position: maps[targetIndex].emittedPosition }; // Closest pos
8787
}
8888

8989
function getOriginalPosition(loc: SourceMappableLocation): SourceMappableLocation {
@@ -94,13 +94,13 @@ namespace ts.sourcemaps {
9494
// if no exact match, closest is 2's compliment of result
9595
targetIndex = ~targetIndex;
9696
}
97-
return { fileName: toPath(maps[targetIndex].sourcePath, sourceRoot, host.getCanonicalFileName), position: maps[targetIndex].sourcePosition }; // Closest pos
97+
return { fileName: getNormalizedAbsolutePath(maps[targetIndex].sourcePath, sourceRoot), position: maps[targetIndex].sourcePosition }; // Closest pos
9898
}
9999

100100
function getSourceFileLike(fileName: string, location: string): SourceFileLike | undefined {
101101
// Lookup file in program, if provided
102102
const path = toPath(fileName, location, host.getCanonicalFileName);
103-
const file = program && program.getSourceFile(path);
103+
const file = program && program.getSourceFileByPath(path);
104104
// file returned here could be .d.ts when asked for .ts file if projectReferences and module resolution created this source file
105105
if (!file || file.resolvedPath !== path) {
106106
// Otherwise check the cache (which may hit disk)

src/services/sourcemaps.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,12 @@ namespace ts {
2323
let sourcemappedFileCache: SourceFileLikeCache;
2424
return { tryGetOriginalLocation, tryGetGeneratedLocation, toLineColumnOffset, clearCache };
2525

26+
function toPath(fileName: string) {
27+
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
28+
}
29+
2630
function scanForSourcemapURL(fileName: string) {
27-
const mappedFile = sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
31+
const mappedFile = sourcemappedFileCache.get(toPath(fileName));
2832
if (!mappedFile) {
2933
return;
3034
}
@@ -88,7 +92,7 @@ namespace ts {
8892
}
8993
possibleMapLocations.push(fileName + ".map");
9094
for (const location of possibleMapLocations) {
91-
const mapPath = toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
95+
const mapPath = ts.toPath(location, getDirectoryPath(fileName), getCanonicalFileName);
9296
if (host.fileExists(mapPath)) {
9397
return convertDocumentToSourceMapper(file, host.readFile(mapPath)!, mapPath); // TODO: GH#18217
9498
}
@@ -120,12 +124,16 @@ namespace ts {
120124
}
121125

122126
function getFile(fileName: string): SourceFileLike | undefined {
123-
return getProgram().getSourceFile(fileName) || sourcemappedFileCache.get(toPath(fileName, currentDirectory, getCanonicalFileName));
127+
const path = toPath(fileName);
128+
const file = getProgram().getSourceFileByPath(path);
129+
if (file && file.resolvedPath === path) {
130+
return file;
131+
}
132+
return sourcemappedFileCache.get(path);
124133
}
125134

126135
function toLineColumnOffset(fileName: string, position: number): LineAndCharacter {
127-
const path = toPath(fileName, currentDirectory, getCanonicalFileName);
128-
const file = getProgram().getSourceFile(path) || sourcemappedFileCache.get(path)!; // TODO: GH#18217
136+
const file = getFile(fileName)!; // TODO: GH#18217
129137
return file.getLineAndCharacterOfPosition(position);
130138
}
131139

src/testRunner/unittests/tsserverProjectSystem.ts

Lines changed: 126 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10562,90 +10562,149 @@ declare class TestLib {
1056210562
});
1056310563

1056410564
describe("tsserverProjectSystem with tsbuild projects", () => {
10565-
function getProjectFiles(project: string): [File, File] {
10566-
return [
10567-
TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json"),
10568-
TestFSWithWatch.getTsBuildProjectFile(project, "index.ts"),
10569-
];
10570-
}
10571-
10572-
const project = "container";
10573-
const containerLib = getProjectFiles("container/lib");
10574-
const containerExec = getProjectFiles("container/exec");
10575-
const containerCompositeExec = getProjectFiles("container/compositeExec");
10576-
const containerConfig = TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json");
10577-
const files = [libFile, ...containerLib, ...containerExec, ...containerCompositeExec, containerConfig];
10578-
10579-
function createHost() {
10565+
function createHost(files: ReadonlyArray<File>, rootNames: ReadonlyArray<string>) {
1058010566
const host = createServerHost(files);
1058110567

1058210568
// ts build should succeed
10583-
const solutionBuilder = tscWatch.createSolutionBuilder(host, [containerConfig.path], {});
10569+
const solutionBuilder = tscWatch.createSolutionBuilder(host, rootNames, {});
1058410570
solutionBuilder.buildAllProjects();
1058510571
assert.equal(host.getOutput().length, 0);
1058610572

1058710573
return host;
1058810574
}
1058910575

10590-
it("does not error on container only project", () => {
10591-
const host = createHost();
10576+
describe("with container project", () => {
10577+
function getProjectFiles(project: string): [File, File] {
10578+
return [
10579+
TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json"),
10580+
TestFSWithWatch.getTsBuildProjectFile(project, "index.ts"),
10581+
];
10582+
}
1059210583

10593-
// Open external project for the folder
10594-
const session = createSession(host);
10595-
const service = session.getProjectService();
10596-
service.openExternalProjects([{
10597-
projectFileName: TestFSWithWatch.getTsBuildProjectFilePath(project, project),
10598-
rootFiles: files.map(f => ({ fileName: f.path })),
10599-
options: {}
10600-
}]);
10601-
checkNumberOfProjects(service, { configuredProjects: 4 });
10602-
files.forEach(f => {
10603-
const args: protocol.FileRequestArgs = {
10604-
file: f.path,
10605-
projectFileName: endsWith(f.path, "tsconfig.json") ? f.path : undefined
10606-
};
10607-
const syntaxDiagnostics = session.executeCommandSeq<protocol.SyntacticDiagnosticsSyncRequest>({
10608-
command: protocol.CommandTypes.SyntacticDiagnosticsSync,
10609-
arguments: args
10610-
}).response;
10611-
assert.deepEqual(syntaxDiagnostics, []);
10612-
const semanticDiagnostics = session.executeCommandSeq<protocol.SemanticDiagnosticsSyncRequest>({
10613-
command: protocol.CommandTypes.SemanticDiagnosticsSync,
10614-
arguments: args
10584+
const project = "container";
10585+
const containerLib = getProjectFiles("container/lib");
10586+
const containerExec = getProjectFiles("container/exec");
10587+
const containerCompositeExec = getProjectFiles("container/compositeExec");
10588+
const containerConfig = TestFSWithWatch.getTsBuildProjectFile(project, "tsconfig.json");
10589+
const files = [libFile, ...containerLib, ...containerExec, ...containerCompositeExec, containerConfig];
10590+
10591+
it("does not error on container only project", () => {
10592+
const host = createHost(files, [containerConfig.path]);
10593+
10594+
// Open external project for the folder
10595+
const session = createSession(host);
10596+
const service = session.getProjectService();
10597+
service.openExternalProjects([{
10598+
projectFileName: TestFSWithWatch.getTsBuildProjectFilePath(project, project),
10599+
rootFiles: files.map(f => ({ fileName: f.path })),
10600+
options: {}
10601+
}]);
10602+
checkNumberOfProjects(service, { configuredProjects: 4 });
10603+
files.forEach(f => {
10604+
const args: protocol.FileRequestArgs = {
10605+
file: f.path,
10606+
projectFileName: endsWith(f.path, "tsconfig.json") ? f.path : undefined
10607+
};
10608+
const syntaxDiagnostics = session.executeCommandSeq<protocol.SyntacticDiagnosticsSyncRequest>({
10609+
command: protocol.CommandTypes.SyntacticDiagnosticsSync,
10610+
arguments: args
10611+
}).response;
10612+
assert.deepEqual(syntaxDiagnostics, []);
10613+
const semanticDiagnostics = session.executeCommandSeq<protocol.SemanticDiagnosticsSyncRequest>({
10614+
command: protocol.CommandTypes.SemanticDiagnosticsSync,
10615+
arguments: args
10616+
}).response;
10617+
assert.deepEqual(semanticDiagnostics, []);
10618+
});
10619+
const containerProject = service.configuredProjects.get(containerConfig.path)!;
10620+
checkProjectActualFiles(containerProject, [containerConfig.path]);
10621+
const optionsDiagnostics = session.executeCommandSeq<protocol.CompilerOptionsDiagnosticsRequest>({
10622+
command: protocol.CommandTypes.CompilerOptionsDiagnosticsFull,
10623+
arguments: { projectFileName: containerProject.projectName }
1061510624
}).response;
10616-
assert.deepEqual(semanticDiagnostics, []);
10625+
assert.deepEqual(optionsDiagnostics, []);
10626+
});
10627+
10628+
it("can successfully find references with --out options", () => {
10629+
const host = createHost(files, [containerConfig.path]);
10630+
const session = createSession(host);
10631+
openFilesForSession([containerCompositeExec[1]], session);
10632+
const service = session.getProjectService();
10633+
checkNumberOfProjects(service, { configuredProjects: 1 });
10634+
const locationOfMyConst = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst");
10635+
const response = session.executeCommandSeq<protocol.RenameRequest>({
10636+
command: protocol.CommandTypes.Rename,
10637+
arguments: {
10638+
file: containerCompositeExec[1].path,
10639+
...locationOfMyConst
10640+
}
10641+
}).response as protocol.RenameResponseBody;
10642+
10643+
10644+
const myConstLen = "myConst".length;
10645+
const locationOfMyConstInLib = protocolLocationFromSubstring(containerLib[1].content, "myConst");
10646+
assert.deepEqual(response.locs, [
10647+
{ file: containerCompositeExec[1].path, locs: [{ start: locationOfMyConst, end: { line: locationOfMyConst.line, offset: locationOfMyConst.offset + myConstLen } }] },
10648+
{ file: containerLib[1].path, locs: [{ start: locationOfMyConstInLib, end: { line: locationOfMyConstInLib.line, offset: locationOfMyConstInLib.offset + myConstLen } }] }
10649+
]);
1061710650
});
10618-
const containerProject = service.configuredProjects.get(containerConfig.path)!;
10619-
checkProjectActualFiles(containerProject, [containerConfig.path]);
10620-
const optionsDiagnostics = session.executeCommandSeq<protocol.CompilerOptionsDiagnosticsRequest>({
10621-
command: protocol.CommandTypes.CompilerOptionsDiagnosticsFull,
10622-
arguments: { projectFileName: containerProject.projectName }
10623-
}).response;
10624-
assert.deepEqual(optionsDiagnostics, []);
1062510651
});
1062610652

10627-
it("can successfully find references with --out options", () => {
10628-
const host = createHost();
10653+
it("can go to definition correctly", () => {
10654+
const projectLocation = "/user/username/projects/myproject";
10655+
const dependecyLocation = `${projectLocation}/dependency`;
10656+
const mainLocation = `${projectLocation}/main`;
10657+
const dependencyTs: File = {
10658+
path: `${dependecyLocation}/FnS.ts`,
10659+
content: `export function fn1() { }
10660+
export function fn2() { }
10661+
export function fn3() { }
10662+
export function fn4() { }
10663+
export function fn5() { }`
10664+
};
10665+
const dependencyConfig: File = {
10666+
path: `${dependecyLocation}/tsconfig.json`,
10667+
content: JSON.stringify({ compilerOptions: { composite: true, declarationMap: true } })
10668+
};
10669+
10670+
const mainTs: File = {
10671+
path: `${mainLocation}/main.ts`,
10672+
content: `import {
10673+
fn1, fn2, fn3, fn4, fn5
10674+
} from '../dependency/fns'
10675+
10676+
fn1();
10677+
fn2();
10678+
fn3();
10679+
fn4();
10680+
fn5();`
10681+
};
10682+
const mainConfig: File = {
10683+
path: `${mainLocation}/tsconfig.json`,
10684+
content: JSON.stringify({
10685+
compilerOptions: { composite: true, declarationMap: true },
10686+
references: [{ path: "../dependency" }]
10687+
})
10688+
};
10689+
10690+
const files = [dependencyTs, dependencyConfig, mainTs, mainConfig, libFile];
10691+
const host = createHost(files, [mainConfig.path]);
1062910692
const session = createSession(host);
10630-
openFilesForSession([containerCompositeExec[1]], session);
1063110693
const service = session.getProjectService();
10694+
openFilesForSession([mainTs], session);
1063210695
checkNumberOfProjects(service, { configuredProjects: 1 });
10633-
const locationOfMyConst = protocolLocationFromSubstring(containerCompositeExec[1].content, "myConst");
10634-
const response = session.executeCommandSeq<protocol.RenameRequest>({
10635-
command: protocol.CommandTypes.Rename,
10636-
arguments: {
10637-
file: containerCompositeExec[1].path,
10638-
...locationOfMyConst
10639-
}
10640-
}).response as protocol.RenameResponseBody;
10641-
10642-
10643-
const myConstLen = "myConst".length;
10644-
const locationOfMyConstInLib = protocolLocationFromSubstring(containerLib[1].content, "myConst");
10645-
assert.deepEqual(response.locs, [
10646-
{ file: containerCompositeExec[1].path, locs: [{ start: locationOfMyConst, end: { line: locationOfMyConst.line, offset: locationOfMyConst.offset + myConstLen } }] },
10647-
{ file: containerLib[1].path, locs: [{ start: locationOfMyConstInLib, end: { line: locationOfMyConstInLib.line, offset: locationOfMyConstInLib.offset + myConstLen } }] }
10648-
]);
10696+
checkProjectActualFiles(service.configuredProjects.get(mainConfig.path)!, [mainTs.path, libFile.path, mainConfig.path, `${dependecyLocation}/fns.d.ts`]);
10697+
for (let i = 0; i < 5; i++) {
10698+
const startSpan = { line: i + 5, offset: 1 };
10699+
const response = session.executeCommandSeq<protocol.DefinitionAndBoundSpanRequest>({
10700+
command: protocol.CommandTypes.DefinitionAndBoundSpan,
10701+
arguments: { file: mainTs.path, ...startSpan }
10702+
}).response as protocol.DefinitionInfoAndBoundSpan;
10703+
assert.deepEqual(response, {
10704+
definitions: [{ file: dependencyTs.path, start: { line: i + 1, offset: 17 }, end: { line: i + 1, offset: 20 } }],
10705+
textSpan: { start: startSpan, end: { line: startSpan.line, offset: startSpan.offset + 3 } }
10706+
});
10707+
}
1064910708
});
1065010709
});
1065110710

0 commit comments

Comments
 (0)