Skip to content

Commit 532600c

Browse files
author
Andy Hanson
committed
Have checker collect a list of suggestion diagnostics instead of redoing work in calculateSuggestionDiagnostics
1 parent ee304c3 commit 532600c

File tree

7 files changed

+33
-40
lines changed

7 files changed

+33
-40
lines changed

src/compiler/checker.ts

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,8 @@ namespace ts {
311311
node = getParseTreeNode(node, isTypeNode);
312312
return node && getTypeArgumentConstraint(node);
313313
},
314+
315+
getSuggestionDiagnostics: file => suggestionDiagnostics.get(file.fileName) || emptyArray,
314316
};
315317

316318
const tupleTypes: GenericType[] = [];
@@ -449,6 +451,19 @@ namespace ts {
449451
const awaitedTypeStack: number[] = [];
450452

451453
const diagnostics = createDiagnosticCollection();
454+
// Suggestion diagnostics must have a file. Keyed by source file name.
455+
const suggestionDiagnostics = createMultiMap<Diagnostic>();
456+
function addSuggestionDiagnostic(diag: Diagnostic): void {
457+
suggestionDiagnostics.add(diag.file.fileName, { ...diag, category: DiagnosticCategory.Suggestion });
458+
}
459+
function addErrorOrSuggestionDiagnostic(isError: boolean, diag: Diagnostic) {
460+
if (isError) {
461+
diagnostics.add(diag);
462+
}
463+
else {
464+
addSuggestionDiagnostic(diag);
465+
}
466+
}
452467

453468
const enum TypeFacts {
454469
None = 0,
@@ -2095,9 +2110,15 @@ namespace ts {
20952110
const diag = Diagnostics.Invalid_module_name_in_augmentation_Module_0_resolves_to_an_untyped_module_at_1_which_cannot_be_augmented;
20962111
error(errorNode, diag, moduleReference, resolvedModule.resolvedFileName);
20972112
}
2098-
else if (noImplicitAny && moduleNotFoundError) {
2099-
diagnostics.add(createDiagnosticForModuleMissingTypes(errorNode, resolvedModule, moduleReference, Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type));
2100-
}
2113+
const errorInfo = resolvedModule.packageId && chainDiagnosticMessages(
2114+
/*details*/ undefined,
2115+
Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0,
2116+
getMangledNameForScopedPackage(resolvedModule.packageId.name));
2117+
addErrorOrSuggestionDiagnostic(noImplicitAny && !!moduleNotFoundError, createDiagnosticForNodeFromMessageChain(errorNode, chainDiagnosticMessages(
2118+
errorInfo,
2119+
Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type,
2120+
moduleReference,
2121+
resolvedModule.resolvedFileName)));
21012122
// Failed imports and untyped modules are both treated in an untyped manner; only difference is whether we give a diagnostic first.
21022123
return undefined;
21032124
}

src/compiler/diagnosticMessages.json

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3818,10 +3818,6 @@
38183818
"category": "Suggestion",
38193819
"code": 80001
38203820
},
3821-
"Did not find a declaration file for module '{0}'. '{1}' implicitly has an 'any' type.": {
3822-
"category": "Suggestion",
3823-
"code": 80002
3824-
},
38253821

38263822
"Add missing 'super()' call": {
38273823
"category": "Message",

src/compiler/program.ts

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2416,26 +2416,10 @@ namespace ts {
24162416
return options.jsx ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_jsx_is_not_set;
24172417
}
24182418
function needAllowJs() {
2419-
return willAllowImplicitAnyJsModule(options) ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
2419+
return options.allowJs || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
24202420
}
24212421
}
24222422

2423-
export function willAllowImplicitAnyJsModule(options: CompilerOptions): boolean {
2424-
return options.allowJs || !getStrictOptionValue(options, "noImplicitAny");
2425-
}
2426-
2427-
export function createDiagnosticForModuleMissingTypes(errorNode: Node, { packageId, resolvedFileName }: ResolvedModuleFull, moduleReference: string, diag: DiagnosticMessage): Diagnostic {
2428-
const errorInfo = packageId && chainDiagnosticMessages(
2429-
/*details*/ undefined,
2430-
Diagnostics.Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_module_0,
2431-
getMangledNameForScopedPackage(packageId.name));
2432-
return createDiagnosticForNodeFromMessageChain(errorNode, chainDiagnosticMessages(
2433-
errorInfo,
2434-
diag,
2435-
moduleReference,
2436-
resolvedFileName));
2437-
}
2438-
24392423
function checkAllDefined(names: string[]): string[] {
24402424
Debug.assert(names.every(name => name !== undefined), "A name is undefined.", () => JSON.stringify(names));
24412425
return names;

src/compiler/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2954,6 +2954,8 @@ namespace ts {
29542954
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
29552955
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
29562956
/* @internal */ getTypeArgumentConstraint(node: TypeNode): Type | undefined;
2957+
2958+
/* @internal */ getSuggestionDiagnostics(file: SourceFile): ReadonlyArray<Diagnostic>;
29572959
}
29582960

29592961
/* @internal */

src/services/codefixes/fixCannotFindModule.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
/* @internal */
22
namespace ts.codefix {
33
const fixId = "fixCannotFindModule";
4-
const errorCodes = [
5-
Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type.code,
6-
Diagnostics.Did_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type.code
7-
];
4+
const errorCodes = [Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type.code];
85
registerCodeFix({
96
errorCodes,
107
getCodeActions: context => {

src/services/suggestionDiagnostics.ts

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,14 @@
11
/* @internal */
22
namespace ts {
33
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program): Diagnostic[] {
4+
program.getSemanticDiagnostics(sourceFile); //todo: assert that this was already done
5+
const checker = program.getDiagnosticsProducingTypeChecker();
46
const diags: Diagnostic[] = [];
57

68
if (sourceFile.commonJsModuleIndicator) {
79
diags.push(createDiagnosticForNode(sourceFile.commonJsModuleIndicator, Diagnostics.File_is_a_CommonJS_module_it_may_be_converted_to_an_ES6_module));
810
}
911

10-
if (willAllowImplicitAnyJsModule(program.getCompilerOptions())) {
11-
for (const importNode of sourceFile.imports) {
12-
const resolved = getResolvedModule(sourceFile, importNode.text);
13-
if (resolved && resolved.isExternalLibraryImport && !extensionIsTypeScript(resolved.extension)) {
14-
diags.push(createDiagnosticForModuleMissingTypes(importNode, resolved, importNode.text, Diagnostics.Did_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type));
15-
}
16-
}
17-
}
18-
19-
return diags;
12+
return diags.concat(checker.getSuggestionDiagnostics(sourceFile));
2013
}
2114
}

tests/cases/fourslash/codeFixCannotFindModule_suggestion.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ test.setTypesRegistry({
1515
verify.noErrors();
1616
goTo.file("/a.ts");
1717
verify.getSuggestionDiagnostics([{
18-
message: "Did not find a declaration file for module 'abs/subModule'. '/node_modules/abs/subModule.js' implicitly has an 'any' type.",
19-
code: 80002,
18+
message: "Could not find a declaration file for module 'abs/subModule'. '/node_modules/abs/subModule.js' implicitly has an 'any' type.",
19+
code: 7016,
2020
}]);
2121

2222
verify.codeFixAvailable([{

0 commit comments

Comments
 (0)