Keep alive declaration script info and map file info if source file info is alive

This commit is contained in:
Sheetal Nandi 2018-11-29 14:14:45 -08:00
parent 0aa4da43ad
commit 56a39b754c
7 changed files with 47 additions and 27 deletions

View File

@ -2197,8 +2197,8 @@ namespace ts.server {
}
/*@internal*/
getDocumentPositionMapper(fileName: string, project: Project): DocumentPositionMapper | undefined {
const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient(fileName, project.currentDirectory, project.directoryStructureHost);
getDocumentPositionMapper(project: Project, generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined {
const declarationInfo = this.getOrCreateScriptInfoNotOpenedByClient(generatedFileName, project.currentDirectory, project.directoryStructureHost);
if (!declarationInfo) return undefined;
declarationInfo.getSnapshot(); // Ensure synchronized
@ -2210,7 +2210,6 @@ namespace ts.server {
// Create the mapper
declarationInfo.mapInfo = undefined;
// TODO: shkamat Lifetime of declarationInfo and mapInfo
let readMapFile: ((fileName: string) => string | undefined) | undefined = fileName => {
const mapInfo = this.getOrCreateScriptInfoNotOpenedByClient(fileName, project.currentDirectory, project.directoryStructureHost);
if (!mapInfo) return undefined;
@ -2227,6 +2226,11 @@ namespace ts.server {
);
readMapFile = undefined; // Remove ref to project
declarationInfo.mapper = mapper || false;
if (sourceFileName && mapper) {
// Attach as source
const sourceInfo = this.getOrCreateScriptInfoNotOpenedByClient(sourceFileName, project.currentDirectory, project.directoryStructureHost)!;
(declarationInfo.mapInfo!.sourceInfos || (declarationInfo.mapInfo!.sourceInfos = createMap())).set(sourceInfo.path, true);
}
return mapper;
}
@ -2609,13 +2613,25 @@ namespace ts.server {
private removeOrphanScriptInfos() {
const toRemoveScriptInfos = cloneMap(this.filenameToScriptInfo);
this.filenameToScriptInfo.forEach(info => {
if (info.isScriptOpen() || !info.isOrphan()) {
toRemoveScriptInfos.delete(info.path);
if (info.mapInfo) {
toRemoveScriptInfos.delete(info.mapInfo.path);
if (info.mapInfo.sourceInfos) {
info.mapInfo.sourceInfos.forEach((_value, path) => toRemoveScriptInfos.delete(path));
}
// If script info is open or orphan, retain it and its dependencies
if (!info.isScriptOpen() && info.isOrphan()) {
// Otherwise if there is any source info that is alive, this alive too
if (!info.mapInfo || !info.mapInfo.sourceInfos) return;
if (!forEachKey(info.mapInfo.sourceInfos, path => {
const info = this.getScriptInfoForPath(path as Path)!;
return info.isScriptOpen() || !info.isOrphan();
})) {
return;
}
}
// Retain this script info
toRemoveScriptInfos.delete(info.path);
if (info.mapInfo) {
// And map file info and source infos
toRemoveScriptInfos.delete(info.mapInfo.path);
if (info.mapInfo.sourceInfos) {
info.mapInfo.sourceInfos.forEach((_value, path) => toRemoveScriptInfos.delete(path));
}
}
});

View File

@ -504,8 +504,8 @@ namespace ts.server {
}
/*@internal*/
getDocumentPositionMapper(fileName: string): DocumentPositionMapper | undefined {
return this.projectService.getDocumentPositionMapper(fileName, this);
getDocumentPositionMapper(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined {
return this.projectService.getDocumentPositionMapper(this, generatedFileName, sourceFileName);
}
/*@internal*/

View File

@ -64,14 +64,20 @@ namespace ts.server {
this.switchToScriptVersionCache();
}
private resetSourceMapInfo() {
this.info.mapper = undefined;
this.info.sourceFileLike = undefined;
this.info.mapInfo = undefined;
this.info.sourceInfos = undefined;
}
/** Public for testing */
public useText(newText?: string) {
this.svc = undefined;
this.text = newText;
this.lineMap = undefined;
this.fileSize = undefined;
this.info.mapper = undefined;
this.info.sourceFileLike = undefined;
this.resetSourceMapInfo();
this.version.text++;
}
@ -81,8 +87,7 @@ namespace ts.server {
this.text = undefined;
this.lineMap = undefined;
this.fileSize = undefined;
this.info.mapper = undefined;
this.info.sourceFileLike = undefined;
this.resetSourceMapInfo();
}
/**
@ -304,7 +309,7 @@ namespace ts.server {
/*@internal*/
sourceInfos?: Map<true>;
/*@internal*/
mapper: DocumentPositionMapper | false | undefined = false;
mapper?: DocumentPositionMapper | false;
/*@internal*/
sourceFileLike: SourceFileLike | undefined;

View File

@ -1145,7 +1145,7 @@ namespace ts {
getProgram,
fileExists: host.fileExists && (f => host.fileExists!(f)),
readFile: host.readFile && ((f, encoding) => host.readFile!(f, encoding)),
getDocumentPositionMapper: host.getDocumentPositionMapper && (f => host.getDocumentPositionMapper!(f)),
getDocumentPositionMapper: host.getDocumentPositionMapper && ((generatedFileName, sourceFileName) => host.getDocumentPositionMapper!(generatedFileName, sourceFileName)),
getSourceFileLike: host.getSourceFileLike && (f => host.getSourceFileLike!(f)),
log
});

View File

@ -16,7 +16,7 @@ namespace ts {
fileExists?(path: string): boolean;
readFile?(path: string, encoding?: string): string | undefined;
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
getDocumentPositionMapper?(fileName: string): DocumentPositionMapper | undefined;
getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined;
log(s: string): void;
}
@ -31,20 +31,20 @@ namespace ts {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
function getDocumentPositionMapper(fileName: string) {
const path = toPath(fileName);
function getDocumentPositionMapper(generatedFileName: string, sourceFileName?: string) {
const path = toPath(generatedFileName);
const value = documentPositionMappers.get(path);
if (value) return value;
let mapper: DocumentPositionMapper | undefined;
if (host.getDocumentPositionMapper) {
mapper = host.getDocumentPositionMapper(fileName);
mapper = host.getDocumentPositionMapper(generatedFileName, sourceFileName);
}
else if (host.readFile) {
const file = getSourceFileLike(fileName);
const file = getSourceFileLike(generatedFileName);
mapper = file && ts.getDocumentPositionMapper(
{ getSourceFileLike, getCanonicalFileName, log: s => host.log(s) },
fileName,
generatedFileName,
getLineInfo(file.text, getLineStarts(file)),
f => !host.fileExists || host.fileExists(f) ? host.readFile!(f) : undefined
);
@ -78,7 +78,7 @@ namespace ts {
getDeclarationEmitOutputFilePathWorker(info.fileName, program.getCompilerOptions(), currentDirectory, program.getCommonSourceDirectory(), getCanonicalFileName);
if (declarationPath === undefined) return undefined;
const newLoc = getDocumentPositionMapper(declarationPath).getGeneratedPosition(info);
const newLoc = getDocumentPositionMapper(declarationPath, info.fileName).getGeneratedPosition(info);
return newLoc === info ? undefined : newLoc;
}

View File

@ -234,7 +234,7 @@ namespace ts {
writeFile?(fileName: string, content: string): void;
/* @internal */
getDocumentPositionMapper?(fileName: string): DocumentPositionMapper | undefined;
getDocumentPositionMapper?(generatedFileName: string, sourceFileName?: string): DocumentPositionMapper | undefined;
/* @internal */
getSourceFileLike?(fileName: string): SourceFileLike | undefined;
}

View File

@ -10757,7 +10757,6 @@ fn5();`
openFilesForSession([dependencyTs, randomFile], session);
checkNumberOfProjects(service, { configuredProjects: 2 });
checkProjectActualFiles(service.configuredProjects.get(dependencyConfig.path)!, [dependencyTs.path, libFile.path, dependencyConfig.path]);
debugger;
for (let i = 0; i < 5; i++) {
const startSpan = { line: i + 1, offset: 17 };
const response = session.executeCommandSeq<protocol.RenameRequest>({