Add error related to file not in rootDir and file not part of included root files at the references

This commit is contained in:
Sheetal Nandi
2019-08-09 11:15:20 -07:00
parent fd515b519e
commit 8ac45805c0
13 changed files with 444 additions and 143 deletions

View File

@@ -552,6 +552,12 @@ namespace ts {
allDiagnostics?: Diagnostic[];
}
interface RefFile extends TextRange {
kind: RefFileKind;
index: number;
file: SourceFile;
}
/**
* Determines if program structure is upto date or needs to be recreated
*/
@@ -717,6 +723,8 @@ namespace ts {
let noDiagnosticsTypeChecker: TypeChecker;
let classifiableNames: UnderscoreEscapedMap<true>;
const ambientModuleNameToUnmodifiedFileName = createMap<string>();
// Todo:: Use this to report why file was included in --extendedDiagnostics
let refFileMap: MultiMap<ts.RefFile> | undefined;
const cachedSemanticDiagnosticsForFile: DiagnosticCache<Diagnostic> = {};
const cachedDeclarationDiagnosticsForFile: DiagnosticCache<DiagnosticWithLocation> = {};
@@ -913,6 +921,7 @@ namespace ts {
getSourceFileByPath,
getSourceFiles: () => files,
getMissingFilePaths: () => missingFilePaths!, // TODO: GH#18217
getRefFileMap: () => refFileMap,
getCompilerOptions: () => options,
getSyntacticDiagnostics,
getOptionsDiagnostics,
@@ -1391,6 +1400,7 @@ namespace ts {
}
missingFilePaths = oldProgram.getMissingFilePaths();
refFileMap = oldProgram.getRefFileMap();
// update fileName -> file mapping
for (const newSourceFile of newSourceFiles) {
@@ -2179,25 +2189,24 @@ namespace ts {
}
/** This has side effects through `findSourceFile`. */
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: SourceFile, refPos?: number, refEnd?: number): void {
getSourceFileFromReferenceWorker(fileName,
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile!, refPos!, refEnd!, packageId), // TODO: GH#18217
(diagnostic, ...args) => {
fileProcessingDiagnostics.add(refFile !== undefined && refEnd !== undefined && refPos !== undefined
? createFileDiagnostic(refFile, refPos, refEnd - refPos, diagnostic, ...args)
: createCompilerDiagnostic(diagnostic, ...args));
},
refFile);
function processSourceFile(fileName: string, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, packageId: PackageId | undefined, refFile?: RefFile): void {
getSourceFileFromReferenceWorker(
fileName,
fileName => findSourceFile(fileName, toPath(fileName), isDefaultLib, ignoreNoDefaultLib, refFile, packageId), // TODO: GH#18217
(diagnostic, ...args) => fileProcessingDiagnostics.add(
createRefFileDiagnostic(refFile, diagnostic, ...args)
),
refFile && refFile.file
);
}
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: SourceFile, refPos: number, refEnd: number): void {
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, existingFileName));
}
else {
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing, fileName, existingFileName));
}
function reportFileNamesDifferOnlyInCasingError(fileName: string, existingFileName: string, refFile: RefFile | undefined): void {
fileProcessingDiagnostics.add(createRefFileDiagnostic(
refFile,
Diagnostics.File_name_0_differs_from_already_included_file_name_1_only_in_casing,
fileName,
existingFileName
));
}
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string): SourceFile {
@@ -2222,7 +2231,7 @@ namespace ts {
}
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: RefFile | undefined, packageId: PackageId | undefined): SourceFile | undefined {
const originalFileName = fileName;
if (filesByName.has(path)) {
const file = filesByName.get(path);
@@ -2239,7 +2248,7 @@ namespace ts {
const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(inputName, currentDirectory);
if (checkedAbsolutePath !== inputAbsolutePath) {
reportFileNamesDifferOnlyInCasingError(inputName, checkedName, refFile, refPos, refEnd);
reportFileNamesDifferOnlyInCasingError(inputName, checkedName, refFile);
}
}
@@ -2266,6 +2275,7 @@ namespace ts {
}
}
addFileToRefFileMap(file || undefined, refFile);
return file || undefined;
}
@@ -2289,15 +2299,17 @@ namespace ts {
}
// We haven't looked for this file, do so now and cache result
const file = host.getSourceFile(fileName, options.target!, hostErrorMessage => { // TODO: GH#18217
if (refFile !== undefined && refPos !== undefined && refEnd !== undefined) {
fileProcessingDiagnostics.add(createFileDiagnostic(refFile, refPos, refEnd - refPos,
Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
}
else {
fileProcessingDiagnostics.add(createCompilerDiagnostic(Diagnostics.Cannot_read_file_0_Colon_1, fileName, hostErrorMessage));
}
}, shouldCreateNewSourceFile);
const file = host.getSourceFile(
fileName,
options.target!,
hostErrorMessage => fileProcessingDiagnostics.add(createRefFileDiagnostic(
refFile,
Diagnostics.Cannot_read_file_0_Colon_1,
fileName,
hostErrorMessage
)),
shouldCreateNewSourceFile
);
if (packageId) {
const packageIdKey = packageIdToString(packageId);
@@ -2331,7 +2343,7 @@ namespace ts {
// for case-sensitive file systems check if we've already seen some file with similar filename ignoring case
const existingFile = filesByNameIgnoreCase!.get(pathLowerCase);
if (existingFile) {
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile, refPos, refEnd);
reportFileNamesDifferOnlyInCasingError(fileName, existingFile.fileName, refFile);
}
else {
filesByNameIgnoreCase!.set(pathLowerCase, file);
@@ -2359,10 +2371,20 @@ namespace ts {
processingOtherFiles!.push(file);
}
}
addFileToRefFileMap(file, refFile);
return file;
}
function addFileToRefFileMap(file: SourceFile | undefined, refFile: RefFile | undefined) {
if (refFile && file) {
(refFileMap || (refFileMap = createMultiMap())).add(file.path, {
kind: refFile.kind,
index: refFile.index,
file: refFile.file.path
});
}
}
function addFileToFilesByName(file: SourceFile | undefined, path: Path, redirectedPath: Path | undefined) {
if (redirectedPath) {
filesByName.set(redirectedPath, file);
@@ -2479,9 +2501,21 @@ namespace ts {
}
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
forEach(file.referencedFiles, ref => {
forEach(file.referencedFiles, (ref, index) => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.originalFileName);
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
processSourceFile(
referencedFileName,
isDefaultLib,
/*ignoreNoDefaultLib*/ false,
/*packageId*/ undefined,
{
kind: RefFileKind.ReferenceFile,
index,
file,
pos: ref.pos,
end: ref.end
}
);
});
}
@@ -2500,12 +2534,25 @@ namespace ts {
// store resolved type directive on the file
const fileName = ref.fileName.toLocaleLowerCase();
setResolvedTypeReferenceDirective(file, fileName, resolvedTypeReferenceDirective);
processTypeReferenceDirective(fileName, resolvedTypeReferenceDirective, file, ref.pos, ref.end);
processTypeReferenceDirective(
fileName,
resolvedTypeReferenceDirective,
{
kind: RefFileKind.TypeReferenceDirective,
index: i,
file,
pos: ref.pos,
end: ref.end
}
);
}
}
function processTypeReferenceDirective(typeReferenceDirective: string, resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
refFile?: SourceFile, refPos?: number, refEnd?: number): void {
function processTypeReferenceDirective(
typeReferenceDirective: string,
resolvedTypeReferenceDirective?: ResolvedTypeReferenceDirective,
refFile?: RefFile
): void {
// If we already found this library as a primary reference - nothing to do
const previousResolution = resolvedTypeReferenceDirectives.get(typeReferenceDirective);
@@ -2518,7 +2565,7 @@ namespace ts {
if (resolvedTypeReferenceDirective.primary) {
// resolved from the primary path
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd); // TODO: GH#18217
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile); // TODO: GH#18217
}
else {
// If we already resolved to this file, it must have been a secondary reference. Check file contents
@@ -2528,12 +2575,15 @@ namespace ts {
if (resolvedTypeReferenceDirective.resolvedFileName !== previousResolution.resolvedFileName) {
const otherFileText = host.readFile(resolvedTypeReferenceDirective.resolvedFileName!);
if (otherFileText !== getSourceFile(previousResolution.resolvedFileName!)!.text) {
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, // TODO: GH#18217
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
typeReferenceDirective,
resolvedTypeReferenceDirective.resolvedFileName,
previousResolution.resolvedFileName
));
fileProcessingDiagnostics.add(
createRefFileDiagnostic(
refFile,
Diagnostics.Conflicting_definitions_for_0_found_at_1_and_2_Consider_installing_a_specific_version_of_this_library_to_resolve_the_conflict,
typeReferenceDirective,
resolvedTypeReferenceDirective.resolvedFileName,
previousResolution.resolvedFileName
)
);
}
}
// don't overwrite previous resolution result
@@ -2541,14 +2591,18 @@ namespace ts {
}
else {
// First resolution of this library
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile, refPos, refEnd);
processSourceFile(resolvedTypeReferenceDirective.resolvedFileName!, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, resolvedTypeReferenceDirective.packageId, refFile);
}
}
if (resolvedTypeReferenceDirective.isExternalLibraryImport) currentNodeModulesDepth--;
}
else {
fileProcessingDiagnostics.add(createDiagnostic(refFile!, refPos!, refEnd!, Diagnostics.Cannot_find_type_definition_file_for_0, typeReferenceDirective)); // TODO: GH#18217
fileProcessingDiagnostics.add(createRefFileDiagnostic(
refFile,
Diagnostics.Cannot_find_type_definition_file_for_0,
typeReferenceDirective
));
}
if (saveResolution) {
@@ -2568,17 +2622,24 @@ namespace ts {
const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts");
const suggestion = getSpellingSuggestion(unqualifiedLibName, libs, identity);
const message = suggestion ? Diagnostics.Cannot_find_lib_definition_for_0_Did_you_mean_1 : Diagnostics.Cannot_find_lib_definition_for_0;
fileProcessingDiagnostics.add(createDiagnostic(file, libReference.pos, libReference.end, message, libName, suggestion));
fileProcessingDiagnostics.add(createFileDiagnostic(
file,
libReference.pos,
libReference.end - libReference.pos,
message,
libName,
suggestion
));
}
});
}
function createDiagnostic(refFile: SourceFile, refPos: number, refEnd: number, message: DiagnosticMessage, ...args: any[]): Diagnostic {
if (refFile === undefined || refPos === undefined || refEnd === undefined) {
function createRefFileDiagnostic(refFile: RefFile | undefined, message: DiagnosticMessage, ...args: any[]): Diagnostic {
if (!refFile) {
return createCompilerDiagnostic(message, ...args);
}
else {
return createFileDiagnostic(refFile, refPos, refEnd - refPos, message, ...args);
return createFileDiagnostic(refFile.file, refFile.pos, refFile.end - refFile.pos, message, ...args);
}
}
@@ -2632,7 +2693,20 @@ namespace ts {
else if (shouldAddFile) {
const path = toPath(resolvedFileName);
const pos = skipTrivia(file.text, file.imports[i].pos);
findSourceFile(resolvedFileName, path, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, file, pos, file.imports[i].end, resolution.packageId);
findSourceFile(
resolvedFileName,
path,
/*isDefaultLib*/ false,
/*ignoreNoDefaultLib*/ false,
{
kind: RefFileKind.Import,
index: i,
file,
pos,
end: file.imports[i].end
},
resolution.packageId
);
}
if (isFromNodeModulesSearch) {
@@ -2654,12 +2728,20 @@ namespace ts {
function checkSourceFilesBelongToPath(sourceFiles: ReadonlyArray<SourceFile>, rootDirectory: string): boolean {
let allFilesBelongToPath = true;
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
let rootPaths: Map<true> | undefined;
for (const sourceFile of sourceFiles) {
if (!sourceFile.isDeclarationFile) {
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
if (!rootPaths) rootPaths = arrayToSet(rootNames, toPath);
addProgramDiagnosticAtRefPath(
sourceFile,
rootPaths,
Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files,
sourceFile.fileName,
rootDirectory
);
allFilesBelongToPath = false;
}
}
@@ -2771,12 +2853,18 @@ namespace ts {
// List of collected files is complete; validate exhautiveness if this is a project with a file list
if (options.composite) {
const rootPaths = rootNames.map(toPath);
const rootPaths = arrayToSet(rootNames, toPath);
for (const file of files) {
// Ignore file that is not emitted
if (!sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)) continue;
if (rootPaths.indexOf(file.path) === -1) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, file.fileName, options.configFilePath || ""));
if (!rootPaths.has(file.path)) {
addProgramDiagnosticAtRefPath(
file,
rootPaths,
Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern,
file.fileName,
options.configFilePath || ""
);
}
}
}
@@ -2984,6 +3072,35 @@ namespace ts {
}
}
function addProgramDiagnosticAtRefPath(file: SourceFile, rootPaths: Map<true>, message: DiagnosticMessage, ...args: (string | number | undefined)[]) {
const refPaths = refFileMap && refFileMap.get(file.path);
const refPathToReportErrorOn = forEach(refPaths, refPath => rootPaths.has(refPath.file) ? refPath : undefined) ||
elementAt(refPaths, 0);
if (refPathToReportErrorOn) {
const refFile = Debug.assertDefined(getSourceFileByPath(refPathToReportErrorOn.file));
const { kind, index } = refPathToReportErrorOn;
let pos: number, end: number;
switch (kind) {
case RefFileKind.Import:
pos = skipTrivia(refFile.text, refFile.imports[index].pos);
end = refFile.imports[index].end;
break;
case RefFileKind.ReferenceFile:
({ pos, end } = refFile.referencedFiles[index]);
break;
case RefFileKind.TypeReferenceDirective:
({ pos, end } = refFile.typeReferenceDirectives[index]);
break;
default:
return Debug.assertNever(kind);
}
programDiagnostics.add(createFileDiagnostic(refFile, pos, end - pos, message, ...args));
}
else {
programDiagnostics.add(createCompilerDiagnostic(message, ...args));
}
}
function verifyProjectReferences() {
const buildInfoPath = !options.noEmit && !options.suppressOutputPathCheck ? getOutputPathForBuildInfo(options) : undefined;
forEachProjectReference(projectReferences, resolvedProjectReferences, (resolvedRef, index, parent) => {