Skip to content

Commit

Permalink
Lazy calculation of expensive file explaining diagnsotics and some ca…
Browse files Browse the repository at this point in the history
…ching to be used to share the diagnostic data (#58398)
  • Loading branch information
sheetalkamat authored May 6, 2024
1 parent 2070713 commit fd81d04
Show file tree
Hide file tree
Showing 49 changed files with 8,088 additions and 170 deletions.
251 changes: 197 additions & 54 deletions src/compiler/program.ts

Large diffs are not rendered by default.

16 changes: 7 additions & 9 deletions src/compiler/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4608,26 +4608,24 @@ export type FileIncludeReason =

/** @internal */
export const enum FilePreprocessingDiagnosticsKind {
FilePreprocessingReferencedDiagnostic,
FilePreprocessingLibReferenceDiagnostic,
FilePreprocessingFileExplainingDiagnostic,
ResolutionDiagnostics,
}

/** @internal */
export interface FilePreprocessingReferencedDiagnostic {
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingReferencedDiagnostic;
reason: ReferencedFile;
diagnostic: DiagnosticMessage;
args?: DiagnosticArguments;
export interface FilePreprocessingLibReferenceDiagnostic {
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingLibReferenceDiagnostic;
reason: ReferencedFile & { kind: FileIncludeKind.LibReferenceDirective; };
}

/** @internal */
export interface FilePreprocessingFileExplainingDiagnostic {
kind: FilePreprocessingDiagnosticsKind.FilePreprocessingFileExplainingDiagnostic;
file?: Path;
file: Path | undefined;
fileProcessingReason: FileIncludeReason;
diagnostic: DiagnosticMessage;
args?: DiagnosticArguments;
args: DiagnosticArguments;
}

/** @internal */
Expand All @@ -4637,7 +4635,7 @@ export interface ResolutionDiagnostics {
}

/** @internal */
export type FilePreprocessingDiagnostics = FilePreprocessingReferencedDiagnostic | FilePreprocessingFileExplainingDiagnostic | ResolutionDiagnostics;
export type FilePreprocessingDiagnostics = FilePreprocessingLibReferenceDiagnostic | FilePreprocessingFileExplainingDiagnostic | ResolutionDiagnostics;

/** @internal */
export const enum EmitOnly {
Expand Down
1 change: 1 addition & 0 deletions src/compiler/watchPublic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,7 @@ export function createWatchProgram<T extends BuilderProgram>(host: WatchCompiler
});
parsedConfigs = undefined;
}
builderProgram = undefined!;
}

function getResolutionCache() {
Expand Down
49 changes: 31 additions & 18 deletions src/testRunner/unittests/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface NamedSourceText {
export interface ProgramWithSourceTexts extends ts.Program {
sourceTexts?: readonly NamedSourceText[];
host: TestCompilerHost;
version: number;
}

export interface TestCompilerHost extends ts.CompilerHost {
Expand Down Expand Up @@ -102,7 +103,7 @@ function createSourceFileWithText(fileName: string, sourceText: SourceText, targ
return file;
}

export function createTestCompilerHost(texts: readonly NamedSourceText[], target: ts.ScriptTarget, oldProgram?: ProgramWithSourceTexts, useGetSourceFileByPath?: boolean) {
export function createTestCompilerHost(texts: readonly NamedSourceText[], target: ts.ScriptTarget, oldProgram?: ProgramWithSourceTexts, useGetSourceFileByPath?: boolean, useCaseSensitiveFileNames?: boolean) {
const files = ts.arrayToMap(texts, t => t.name, t => {
if (oldProgram) {
let oldFile = oldProgram.getSourceFile(t.name) as SourceFileWithText;
Expand All @@ -115,52 +116,64 @@ export function createTestCompilerHost(texts: readonly NamedSourceText[], target
}
return createSourceFileWithText(t.name, t.text, target);
});
const useCaseSensitiveFileNames = ts.sys && ts.sys.useCaseSensitiveFileNames;
if (useCaseSensitiveFileNames === undefined) useCaseSensitiveFileNames = ts.sys && ts.sys.useCaseSensitiveFileNames;
const getCanonicalFileName = ts.createGetCanonicalFileName(useCaseSensitiveFileNames);
const filesByPath = ts.mapEntries(files, (fileName, file) => [ts.toPath(fileName, "", getCanonicalFileName), file]);
const trace: string[] = [];
const result: TestCompilerHost = {
trace: s => trace.push(s),
getTrace: () => trace,
clearTrace: () => trace.length = 0,
getSourceFile: fileName => files.get(fileName),
getSourceFile: fileName => filesByPath.get(ts.toPath(fileName, "", getCanonicalFileName)),
getDefaultLibFileName: () => "lib.d.ts",
writeFile: ts.notImplemented,
getCurrentDirectory: () => "",
getDirectories: () => [],
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => ts.sys ? ts.sys.newLine : newLine,
fileExists: fileName => files.has(fileName),
fileExists: fileName => filesByPath.has(ts.toPath(fileName, "", getCanonicalFileName)),
readFile: fileName => {
const file = files.get(fileName);
const file = filesByPath.get(ts.toPath(fileName, "", getCanonicalFileName));
return file && file.text;
},
};
if (useGetSourceFileByPath) {
const filesByPath = ts.mapEntries(files, (fileName, file) => [ts.toPath(fileName, "", getCanonicalFileName), file]);
result.getSourceFileByPath = (_fileName, path) => filesByPath.get(path);
}
return result;
}

export function newProgram(texts: NamedSourceText[], rootNames: string[], options: ts.CompilerOptions, useGetSourceFileByPath?: boolean): ProgramWithSourceTexts {
const host = createTestCompilerHost(texts, options.target!, /*oldProgram*/ undefined, useGetSourceFileByPath);
const program = ts.createProgram(rootNames, options, host) as ProgramWithSourceTexts;
program.sourceTexts = texts;
program.host = host;
return program;
export function newProgram(texts: NamedSourceText[], rootNames: string[], options: ts.CompilerOptions, useGetSourceFileByPath?: boolean, useCaseSensitiveFileNames?: boolean): ProgramWithSourceTexts {
const host = createTestCompilerHost(texts, options.target!, /*oldProgram*/ undefined, useGetSourceFileByPath, useCaseSensitiveFileNames);
return programToProgramWithSourceTexts(
ts.createProgram(rootNames, options, host),
texts,
host,
1,
);
}

export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: readonly string[], options: ts.CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[], useGetSourceFileByPath?: boolean) {
function programToProgramWithSourceTexts(program: ts.Program, texts: NamedSourceText[], host: TestCompilerHost, version: number): ProgramWithSourceTexts {
const result = program as ProgramWithSourceTexts;
result.sourceTexts = texts;
result.host = host;
result.version = version;
return result;
}

export function updateProgram(oldProgram: ProgramWithSourceTexts, rootNames: readonly string[], options: ts.CompilerOptions, updater: (files: NamedSourceText[]) => void, newTexts?: NamedSourceText[], useGetSourceFileByPath?: boolean, useCaseSensitiveFileNames?: boolean) {
if (!newTexts) {
newTexts = oldProgram.sourceTexts!.slice(0);
}
updater(newTexts);
const host = createTestCompilerHost(newTexts, options.target!, oldProgram, useGetSourceFileByPath);
const program = ts.createProgram(rootNames, options, host, oldProgram) as ProgramWithSourceTexts;
program.sourceTexts = newTexts;
program.host = host;
return program;
const host = createTestCompilerHost(newTexts, options.target!, oldProgram, useGetSourceFileByPath, useCaseSensitiveFileNames);
return programToProgramWithSourceTexts(
ts.createProgram(rootNames, options, host, oldProgram),
newTexts,
host,
oldProgram.version + 1,
);
}

export function updateProgramText(files: readonly NamedSourceText[], fileName: string, newProgramText: string) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { dedent } from "../../_namespaces/Utils";
import { jsonToReadableText } from "../helpers";
import {
FsContents,
libContent,
} from "./contents";
import { libFile } from "./virtualFileSystemWithWatch";

export function getFsContentsForMultipleErrorsForceConsistentCasingInFileNames(): FsContents {
return {
"/home/src/projects/project/src/struct.d.ts": dedent`
import * as xs1 from "fp-ts/lib/Struct";
import * as xs2 from "fp-ts/lib/struct";
import * as xs3 from "./Struct";
import * as xs4 from "./struct";
`,
"/home/src/projects/project/src/anotherFile.ts": dedent`
import * as xs1 from "fp-ts/lib/Struct";
import * as xs2 from "fp-ts/lib/struct";
import * as xs3 from "./Struct";
import * as xs4 from "./struct";
`,
"/home/src/projects/project/src/oneMore.ts": dedent`
import * as xs1 from "fp-ts/lib/Struct";
import * as xs2 from "fp-ts/lib/struct";
import * as xs3 from "./Struct";
import * as xs4 from "./struct";
`,
"/home/src/projects/project/tsconfig.json": jsonToReadableText({}),
"/home/src/projects/project/node_modules/fp-ts/lib/struct.d.ts": `export function foo(): void`,
[libFile.path]: libContent,
};
}
43 changes: 43 additions & 0 deletions src/testRunner/unittests/helpers/libraryResolution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,46 @@ export function getCommandLineArgsForLibResolution(withoutConfig: true | undefin
["project1/core.d.ts", "project1/utils.d.ts", "project1/file.ts", "project1/index.ts", "project1/file2.ts", "--lib", "es5,dom", "--traceResolution", "--explainFiles"] :
["-p", "project1", "--explainFiles"];
}

function getFsContentsForLibResolutionUnknown(): FsContents {
return {
"/home/src/projects/project1/utils.d.ts": `export const y = 10;`,
"/home/src/projects/project1/file.ts": `export const file = 10;`,
"/home/src/projects/project1/core.d.ts": `export const core = 10;`,
"/home/src/projects/project1/index.ts": `export const x = "type1";`,
"/home/src/projects/project1/file2.ts": dedent`
/// <reference lib="webworker2"/>
/// <reference lib="unknownlib"/>
/// <reference lib="scripthost"/>
`,
"/home/src/projects/project1/tsconfig.json": jsonToReadableText({
compilerOptions: {
composite: true,
traceResolution: true,
},
}),
"/home/src/lib/lib.d.ts": libContent,
"/home/src/lib/lib.webworker.d.ts": "interface WebWorkerInterface { }",
"/home/src/lib/lib.scripthost.d.ts": "interface ScriptHostInterface { }",
};
}

export function getFsForLibResolutionUnknown() {
return loadProjectFromFiles(
getFsContentsForLibResolutionUnknown(),
{
cwd: "/home/src/projects",
executingFilePath: "/home/src/lib/tsc.js",
},
);
}

export function getSysForLibResolutionUnknown() {
return createWatchedSystem(
getFsContentsForLibResolutionUnknown(),
{
currentDirectory: "/home/src/projects",
executingFilePath: "/home/src/lib/tsc.js",
},
);
}
Loading

0 comments on commit fd81d04

Please sign in to comment.