Skip to content

Commit 52e8c2d

Browse files
committed
Unused variable error reporting needs to handle nodes that could not belong to current source file
Eg. when resolving module, the another file gets checked and its locals are added to potentiallyUnused list Fixes #24215
1 parent d82d35c commit 52e8c2d

File tree

2 files changed

+45
-13
lines changed

2 files changed

+45
-13
lines changed

src/compiler/checker.ts

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ namespace ts {
319319
checkSourceFile(file);
320320
const diagnostics: Diagnostic[] = [];
321321
Debug.assert(!!(getNodeLinks(file).flags & NodeCheckFlags.TypeChecked));
322-
checkUnusedIdentifiers(allPotentiallyUnusedIdentifiers.get(file.fileName)!, (kind, diag) => {
322+
checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(file), (kind, diag) => {
323323
if (!unusedIsError(kind)) {
324324
diagnostics.push({ ...diag, category: DiagnosticCategory.Suggestion });
325325
}
@@ -450,9 +450,7 @@ namespace ts {
450450
let deferredGlobalExtractSymbol: Symbol;
451451

452452
let deferredNodes: Node[];
453-
const allPotentiallyUnusedIdentifiers = createMap<ReadonlyArray<PotentiallyUnusedIdentifier>>(); // key is file name
454-
let potentiallyUnusedIdentifiers: PotentiallyUnusedIdentifier[]; // Potentially unused identifiers in the source file currently being checked.
455-
const seenPotentiallyUnusedIdentifiers = createMap<true>(); // For assertion that we don't defer the same identifier twice
453+
const allPotentiallyUnusedIdentifiers = createMap<PotentiallyUnusedIdentifier[]>(); // key is file name
456454

457455
let flowLoopStart = 0;
458456
let flowLoopCount = 0;
@@ -22557,7 +22555,13 @@ namespace ts {
2255722555

2255822556
function registerForUnusedIdentifiersCheck(node: PotentiallyUnusedIdentifier): void {
2255922557
// May be in a call such as getTypeOfNode that happened to call this. But potentiallyUnusedIdentifiers is only defined in the scope of `checkSourceFile`.
22560-
if (potentiallyUnusedIdentifiers) {
22558+
if (produceDiagnostics) {
22559+
const sourceFile = getSourceFileOfNode(node);
22560+
let potentiallyUnusedIdentifiers = allPotentiallyUnusedIdentifiers.get(sourceFile.path);
22561+
if (!potentiallyUnusedIdentifiers) {
22562+
potentiallyUnusedIdentifiers = [];
22563+
allPotentiallyUnusedIdentifiers.set(sourceFile.path, potentiallyUnusedIdentifiers);
22564+
}
2256122565
// TODO: GH#22580
2256222566
// Debug.assert(addToSeen(seenPotentiallyUnusedIdentifiers, getNodeId(node)), "Adding potentially-unused identifier twice");
2256322567
potentiallyUnusedIdentifiers.push(node);
@@ -25539,6 +25543,10 @@ namespace ts {
2553925543
}
2554025544
}
2554125545

25546+
function getPotentiallyUnusedIdentifiers(sourceFile: SourceFile): ReadonlyArray<PotentiallyUnusedIdentifier> {
25547+
return allPotentiallyUnusedIdentifiers.get(sourceFile.path) || emptyArray;
25548+
}
25549+
2554225550
// Fully type check a source file and collect the relevant diagnostics.
2554325551
function checkSourceFileWorker(node: SourceFile) {
2554425552
const links = getNodeLinks(node);
@@ -25557,11 +25565,6 @@ namespace ts {
2555725565
clear(potentialNewTargetCollisions);
2555825566

2555925567
deferredNodes = [];
25560-
if (produceDiagnostics) {
25561-
Debug.assert(!allPotentiallyUnusedIdentifiers.has(node.fileName));
25562-
allPotentiallyUnusedIdentifiers.set(node.fileName, potentiallyUnusedIdentifiers = []);
25563-
}
25564-
2556525568
forEach(node.statements, checkSourceElement);
2556625569

2556725570
checkDeferredNodes();
@@ -25571,16 +25574,14 @@ namespace ts {
2557125574
}
2557225575

2557325576
if (!node.isDeclarationFile && (compilerOptions.noUnusedLocals || compilerOptions.noUnusedParameters)) {
25574-
checkUnusedIdentifiers(potentiallyUnusedIdentifiers, (kind, diag) => {
25577+
checkUnusedIdentifiers(getPotentiallyUnusedIdentifiers(node), (kind, diag) => {
2557525578
if (unusedIsError(kind)) {
2557625579
diagnostics.add(diag);
2557725580
}
2557825581
});
2557925582
}
2558025583

2558125584
deferredNodes = undefined;
25582-
seenPotentiallyUnusedIdentifiers.clear();
25583-
potentiallyUnusedIdentifiers = undefined;
2558425585

2558525586
if (isExternalOrCommonJsModule(node)) {
2558625587
checkExternalModuleExports(node);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
/// <reference path='fourslash.ts' />
2+
3+
//@allowJs: true
4+
5+
// @Filename: /mymodule.js
6+
////(function ([|root|], factory) {
7+
//// module.exports = factory();
8+
////}(this, function () {
9+
//// var [|unusedVar|] = "something";
10+
//// return {};
11+
////}));
12+
13+
// @Filename: /app.js
14+
//////@ts-check
15+
////require("./mymodule");
16+
17+
const [range0, range1] = test.ranges();
18+
19+
goTo.file("/app.js");
20+
verify.getSuggestionDiagnostics([]);
21+
22+
goTo.file("/mymodule.js");
23+
verify.getSuggestionDiagnostics([{
24+
message: "'root' is declared but its value is never read.",
25+
code: 6133,
26+
range: range0
27+
}, {
28+
message: "'unusedVar' is declared but its value is never read.",
29+
code: 6133,
30+
range: range1
31+
}]);

0 commit comments

Comments
 (0)