@cplieger/deadset-ts 8.0.0-dev.4 → 8.0.0-dev.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/analysis.js +3 -3
- package/dist/src/config.js +1 -1
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/contract/contract.generated.js +1071 -0
- package/dist/src/contract/report.generated.js +796 -0
- package/dist/src/convention-rows.js +1 -1
- package/dist/src/exempt-classes.js +1 -59
- package/dist/src/exempt.js +8 -19
- package/dist/src/findings/completion.js +11 -20
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +4 -4
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +8 -7
- package/dist/src/findings/non-code-artifacts.js +5 -6
- package/dist/src/findings/reads-and-writes.js +9 -8
- package/dist/src/findings/self-check.js +7 -10
- package/dist/src/findings/unused-declarations.js +28 -27
- package/dist/src/findings/visibility-narrowing.js +9 -11
- package/dist/src/findings-pass.js +1 -3
- package/dist/src/index.js +1 -1
- package/dist/src/intra-function-parts.js +8 -13
- package/dist/src/kinds.js +4 -360
- package/dist/src/report-schema.js +273 -0
- package/dist/src/report.js +17 -11
- package/dist/src/resolve.js +1 -6
- package/dist/src/run.js +2 -1
- package/dist/src/setup-failure.js +2 -6
- package/dist/src/suppress-file.js +4 -3
- package/dist/src/suppress-inline.js +3 -2
- package/dist/src/suppress.js +29 -48
- package/dist/src/verbs/analyze.js +7 -2
- package/dist/src/verbs/describe.js +4 -4
- package/dist/src/verbs/explain.js +2 -1
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +2 -1
- package/dist/src/verbs/print-retained.js +2 -1
- package/dist/src/verbs/print-roots.js +2 -1
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +2 -2
- package/jsr.json +1 -1
- package/package.json +3 -2
- package/src/analysis.ts +3 -3
- package/src/config.ts +7 -13
- package/src/conformance-record.ts +1 -1
- package/src/contract/contract.generated.ts +1123 -0
- package/src/contract/report.generated.ts +1157 -0
- package/src/convention-rows.ts +1 -1
- package/src/exempt-classes.ts +1 -70
- package/src/exempt.ts +12 -20
- package/src/finding.ts +9 -9
- package/src/findings/completion.ts +22 -23
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +6 -7
- package/src/findings/emitters.ts +6 -6
- package/src/findings/interfaces.ts +4 -6
- package/src/findings/intra-function.ts +8 -8
- package/src/findings/non-code-artifacts.ts +5 -7
- package/src/findings/reads-and-writes.ts +13 -11
- package/src/findings/self-check.ts +8 -15
- package/src/findings/unused-declarations.ts +28 -27
- package/src/findings/visibility-narrowing.ts +9 -12
- package/src/findings-pass.ts +1 -4
- package/src/index.ts +1 -1
- package/src/intra-function-parts.ts +8 -14
- package/src/kinds.ts +6 -406
- package/src/report-schema.ts +366 -0
- package/src/report.ts +42 -195
- package/src/reporters/annotations.ts +2 -2
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -2
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +13 -8
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +11 -11
- package/src/run.ts +2 -1
- package/src/setup-failure.ts +5 -7
- package/src/suppress-file.ts +3 -4
- package/src/suppress-inline.ts +2 -2
- package/src/suppress.ts +39 -55
- package/src/verbs/analyze.ts +16 -4
- package/src/verbs/describe.ts +10 -4
- package/src/verbs/explain.ts +2 -1
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +2 -1
- package/src/verbs/print-retained.ts +2 -1
- package/src/verbs/print-roots.ts +2 -1
- package/src/verbs/verb.ts +0 -6
- package/src/verbs/version.ts +2 -2
- package/dist/src/version.js +0 -7
- package/src/version.ts +0 -7
|
@@ -1,62 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* The exemption classes of the Contract's vocabulary, in its order: each class's name, its
|
|
3
|
-
* languages and, for a TypeScript class, which private members it may retain. The rows are
|
|
4
|
-
* written out, as the fixed severity codes are, and a test holds them equal to the Contract.
|
|
5
|
-
* A class name is a type, so a table or a record naming a class outside the vocabulary, or
|
|
6
|
-
* one of another language only, does not compile.
|
|
7
|
-
*/
|
|
8
|
-
/** Every class of the vocabulary, in the order the Contract lists them. */
|
|
9
|
-
export const EXEMPTION_CLASSES = [
|
|
10
|
-
{
|
|
11
|
-
class: "interface-satisfaction",
|
|
12
|
-
languages: ["go", "ts"],
|
|
13
|
-
typescriptVisibility: { private: false, privateName: false },
|
|
14
|
-
},
|
|
15
|
-
{ class: "encoding-reflection", languages: ["go"] },
|
|
16
|
-
{ class: "format-verb-contract", languages: ["go"] },
|
|
17
|
-
{ class: "errors-duck-typing", languages: ["go"] },
|
|
18
|
-
{
|
|
19
|
-
class: "enum-group",
|
|
20
|
-
languages: ["go", "ts"],
|
|
21
|
-
typescriptVisibility: { private: false, privateName: false },
|
|
22
|
-
},
|
|
23
|
-
{
|
|
24
|
-
class: "generated-file",
|
|
25
|
-
languages: ["go", "ts"],
|
|
26
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
27
|
-
},
|
|
28
|
-
{ class: "linkname-cgo-asm-plugin", languages: ["go"] },
|
|
29
|
-
{
|
|
30
|
-
class: "template-field",
|
|
31
|
-
languages: ["go", "ts"],
|
|
32
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
class: "reflective-lookup",
|
|
36
|
-
languages: ["go", "ts"],
|
|
37
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
class: "decorator",
|
|
41
|
-
languages: ["ts"],
|
|
42
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
43
|
-
},
|
|
44
|
-
{
|
|
45
|
-
class: "injection-container",
|
|
46
|
-
languages: ["ts"],
|
|
47
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
class: "framework-lifecycle",
|
|
51
|
-
languages: ["ts"],
|
|
52
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
53
|
-
},
|
|
54
|
-
{
|
|
55
|
-
class: "serialization-contract",
|
|
56
|
-
languages: ["ts"],
|
|
57
|
-
typescriptVisibility: { private: true, privateName: false },
|
|
58
|
-
},
|
|
59
|
-
];
|
|
1
|
+
import { EXEMPTION_CLASSES } from "./contract/contract.generated.js";
|
|
60
2
|
function runsOnTS(row) {
|
|
61
3
|
const languages = row.languages;
|
|
62
4
|
return languages.includes("ts");
|
package/dist/src/exempt.js
CHANGED
|
@@ -6,8 +6,9 @@
|
|
|
6
6
|
* which records held something back. It names no class's detector: the composition
|
|
7
7
|
* hands it the table of the classes it has.
|
|
8
8
|
*/
|
|
9
|
+
import { EXEMPTION_CLASSES } from "./contract/contract.generated.js";
|
|
9
10
|
import { ConfigError } from "./config.js";
|
|
10
|
-
import {
|
|
11
|
+
import { isExemptionClass, TS_EXEMPTION_CLASSES, typescriptVisibilityOf, } from "./exempt-classes.js";
|
|
11
12
|
import { byPosition, positionKey } from "./position.js";
|
|
12
13
|
import { Unanswerable } from "./query.js";
|
|
13
14
|
import { sweep } from "./sweep.js";
|
|
@@ -40,20 +41,8 @@ function retainable(allowed, visibility) {
|
|
|
40
41
|
}
|
|
41
42
|
return true;
|
|
42
43
|
}
|
|
43
|
-
/**
|
|
44
|
-
|
|
45
|
-
* back whole. A class with no row here holds back every declaration but a file.
|
|
46
|
-
*/
|
|
47
|
-
const RETAINABLE = new Map([
|
|
48
|
-
["interface-satisfaction", new Set(["method", "class-member"])],
|
|
49
|
-
["enum-group", new Set(["enum-member"])],
|
|
50
|
-
["injection-container", new Set(["method", "class-member"])],
|
|
51
|
-
["framework-lifecycle", new Set(["method", "class-member"])],
|
|
52
|
-
[
|
|
53
|
-
"serialization-contract",
|
|
54
|
-
new Set(["method", "class-member", "interface-method", "type-member"]),
|
|
55
|
-
],
|
|
56
|
-
]);
|
|
44
|
+
/** The kinds of declaration each class can hold back, which a detector that stops holds back whole. */
|
|
45
|
+
const RETAINABLE = new Map(EXEMPTION_CLASSES.flatMap((row) => "ts" in row.retainsKinds ? [[row.class, new Set(row.retainsKinds.ts)]] : []));
|
|
57
46
|
/** The detail of a record a detector that could not finish holds. */
|
|
58
47
|
const UNANSWERED_DETAIL = "kept live by a question the checker did not answer";
|
|
59
48
|
/** Whether one record is held by a detector that could not finish. */
|
|
@@ -76,7 +65,7 @@ function detected(exemptionClass, detect, input) {
|
|
|
76
65
|
}
|
|
77
66
|
const kinds = RETAINABLE.get(exemptionClass);
|
|
78
67
|
return input.held.symbols
|
|
79
|
-
.filter((symbol) =>
|
|
68
|
+
.filter((symbol) => kinds?.has(symbol.kind) === true)
|
|
80
69
|
.map((symbol) => ({ id: symbol.id, detail: UNANSWERED_DETAIL, site: symbol.position }));
|
|
81
70
|
}
|
|
82
71
|
}
|
|
@@ -197,8 +186,8 @@ export function retainedIn(matrix, input, writeOnly = new Set()) {
|
|
|
197
186
|
return matrix.union.symbols.flatMap((symbol) => held.get(symbol.id) ?? []);
|
|
198
187
|
}
|
|
199
188
|
/**
|
|
200
|
-
* One line per held-back declaration, in site order: its reference, then
|
|
201
|
-
* class, site and detail, all separated by tabs.
|
|
189
|
+
* One line per held-back declaration, in site order: its reference and position, then
|
|
190
|
+
* each record's class, site and detail, all separated by tabs.
|
|
202
191
|
*/
|
|
203
192
|
export function retainedLines(symbols, retained) {
|
|
204
193
|
const held = byDeclaration(retained);
|
|
@@ -212,6 +201,6 @@ export function retainedLines(symbols, retained) {
|
|
|
212
201
|
positionKey(record.site),
|
|
213
202
|
record.detail,
|
|
214
203
|
]);
|
|
215
|
-
return [[symbol.ref, ...fields].join("\t")];
|
|
204
|
+
return [[symbol.ref, positionKey(symbol.position), ...fields].join("\t")];
|
|
216
205
|
});
|
|
217
206
|
}
|
|
@@ -3,29 +3,20 @@
|
|
|
3
3
|
* the code's row of the issue-kind vocabulary, and the dials that withhold a finding
|
|
4
4
|
* together with every finding that falls with a root they withhold.
|
|
5
5
|
*/
|
|
6
|
+
import { CODE, FAMILY_KEY_LENGTH, KIND_ROWS, } from "../contract/contract.generated.js";
|
|
6
7
|
import { componentId } from "../components.js";
|
|
7
8
|
import { deadComponents } from "../matrix.js";
|
|
8
9
|
import { OUTSIDE } from "../graph.js";
|
|
9
10
|
import { KINDS } from "../kinds.js";
|
|
10
11
|
import { byPosition, positionKey } from "../position.js";
|
|
11
12
|
import { declarationKey } from "../ref.js";
|
|
12
|
-
import { FAMILY_KEY_LENGTH } from "../resolve.js";
|
|
13
13
|
import { isPartSubject, isRowSubject } from "../suppress.js";
|
|
14
|
-
/** The unused-file code, whose deletion removes every use its file writes. */
|
|
15
|
-
const FILE_NEVER_IMPORTED = "DS1502";
|
|
16
14
|
/**
|
|
17
|
-
* The codes whose subject the run that counts test references holds live,
|
|
18
|
-
*
|
|
19
|
-
* none of a dead declaration's sweep facts.
|
|
15
|
+
* The codes whose subject the run that counts test references holds live, so a test
|
|
16
|
+
* file's candidate reported under one carries none of a dead declaration's sweep facts.
|
|
20
17
|
*/
|
|
21
|
-
const LIVE_SUBJECT = new Set(
|
|
22
|
-
|
|
23
|
-
"DS1102",
|
|
24
|
-
"DS1104",
|
|
25
|
-
"DS1204",
|
|
26
|
-
"DS1301",
|
|
27
|
-
]);
|
|
28
|
-
/** The fixability grammar/analysis.md "Fixability" gives a finding about a held declaration. */
|
|
18
|
+
const LIVE_SUBJECT = new Set(KIND_ROWS.filter((row) => row.holdsLive).map((row) => row.code));
|
|
19
|
+
/** The fixability grammar/analysis/fixability.md gives a finding about a held declaration. */
|
|
29
20
|
const MANUAL = "manual";
|
|
30
21
|
/** The member kinds an object property can declare, which an `in` expression tests by name. */
|
|
31
22
|
const IN_TESTED = new Set([
|
|
@@ -147,7 +138,7 @@ function testCeilings(input, classOf) {
|
|
|
147
138
|
}
|
|
148
139
|
/**
|
|
149
140
|
* The subjects dead only because production code only tests use is: each declaration the
|
|
150
|
-
* sweep marks test-used, each `
|
|
141
|
+
* sweep marks test-used, each `DS1602` file of such code, and each test of dead code every
|
|
151
142
|
* target of which is one. Nothing they hold references a dead declaration outside them, so
|
|
152
143
|
* the rest of a component they share is reported without them.
|
|
153
144
|
*/
|
|
@@ -224,13 +215,13 @@ function membersListed(swept) {
|
|
|
224
215
|
.sort((a, b) => byPosition(a.position, b.position));
|
|
225
216
|
}
|
|
226
217
|
/**
|
|
227
|
-
* The run's dead components with each file a `
|
|
218
|
+
* The run's dead components with each file a `DS1602` finding reports dead among them, so
|
|
228
219
|
* the file's declarations fall with it, and with the components each subject that is no
|
|
229
220
|
* declaration falls with joined into one.
|
|
230
221
|
*/
|
|
231
222
|
function runComponents(swept, findings) {
|
|
232
223
|
const union = swept.matrix.union;
|
|
233
|
-
const reported = new Set(findings.filter((one) => one.code ===
|
|
224
|
+
const reported = new Set(findings.filter((one) => one.code === CODE.fileNeverImported).map((one) => one.position.path));
|
|
234
225
|
const files = new Map(union.symbols.flatMap((symbol, at) => symbol.kind === "file" && reported.has(symbol.position.path) ? [[at, symbol]] : []));
|
|
235
226
|
const computed = files.size === 0
|
|
236
227
|
? swept.sweep.components
|
|
@@ -330,7 +321,7 @@ export function completed(input, findings, kinds = KINDS) {
|
|
|
330
321
|
: candidates.get(judged.id);
|
|
331
322
|
const fallsWith = finding.fallsWith?.[0];
|
|
332
323
|
const joined = fallsWith === undefined ? undefined : componentOf(fallsWith);
|
|
333
|
-
const file = finding.code ===
|
|
324
|
+
const file = finding.code === CODE.fileNeverImported ? files.get(finding.position.path) : undefined;
|
|
334
325
|
const found = joined !== undefined
|
|
335
326
|
? { ...joined, root: false }
|
|
336
327
|
: file !== undefined
|
|
@@ -376,7 +367,7 @@ export function completed(input, findings, kinds = KINDS) {
|
|
|
376
367
|
const ownClass = judged === undefined ? (finding.reachabilityClass ?? "certain") : classOf(judged.id);
|
|
377
368
|
const used = judged !== undefined
|
|
378
369
|
? candidate !== undefined && testUsed.declarations.has(judged.id)
|
|
379
|
-
: finding.code ===
|
|
370
|
+
: finding.code === CODE.fileNeverImported && testUsed.files.has(finding.position.path);
|
|
380
371
|
const reachabilityClass = used && candidate?.testOfDeadCode !== true ? "possible" : ownClass;
|
|
381
372
|
const configurations = candidate?.configurations ??
|
|
382
373
|
(judged === undefined && !part
|
|
@@ -396,7 +387,7 @@ export function completed(input, findings, kinds = KINDS) {
|
|
|
396
387
|
? undefined
|
|
397
388
|
: candidate !== undefined
|
|
398
389
|
? input.dependencies.lastUses.get(candidate.id)
|
|
399
|
-
: finding.code ===
|
|
390
|
+
: finding.code === CODE.fileNeverImported
|
|
400
391
|
? input.dependencies.fileLastUses.get(finding.position.path)
|
|
401
392
|
: undefined;
|
|
402
393
|
return {
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { declarationKey } from "../dependencies.js";
|
|
2
3
|
import { renderRef } from "../ref.js";
|
|
3
4
|
import { nonCodeArtifacts } from "./non-code-artifacts.js";
|
|
4
|
-
const UNUSED_DEPENDENCY = "DS1601";
|
|
5
|
-
const FILE_NEVER_IMPORTED = "DS1502";
|
|
6
5
|
const MESSAGES = {
|
|
7
6
|
dependency: "no import in the target needs the declared dependency",
|
|
8
7
|
"dev-dependency": "no import in the target needs the declared development dependency",
|
|
@@ -25,7 +24,7 @@ function deadCode(input) {
|
|
|
25
24
|
const reachedOnly = new Set(swept.sweep.candidates.filter((one) => one.relation === "reachability").map((one) => one.id));
|
|
26
25
|
for (const finding of nonCodeArtifacts(input)) {
|
|
27
26
|
const id = files.get(finding.position.path);
|
|
28
|
-
if (finding.code ===
|
|
27
|
+
if (finding.code === CODE.fileNeverImported && id !== undefined) {
|
|
29
28
|
dead.add(id);
|
|
30
29
|
if (finding.unreachableOnly === true) {
|
|
31
30
|
reachedOnly.add(id);
|
|
@@ -57,7 +56,7 @@ function unusedDependencies(input, dependencies) {
|
|
|
57
56
|
const atPossible = unbuilt || users?.some((id) => published.has(id)) === true;
|
|
58
57
|
return [
|
|
59
58
|
{
|
|
60
|
-
code:
|
|
59
|
+
code: CODE.unusedDependency,
|
|
61
60
|
position: dependency.position,
|
|
62
61
|
symbol: {
|
|
63
62
|
ref: renderRef(dependency.manifest, {
|
|
@@ -80,5 +79,5 @@ function unusedDependencies(input, dependencies) {
|
|
|
80
79
|
];
|
|
81
80
|
});
|
|
82
81
|
}
|
|
83
|
-
/** The findings of the dependencies
|
|
82
|
+
/** The findings of the dependencies family, `DS1700` to `DS1799`. */
|
|
84
83
|
export const dependenciesAndModuleMachinery = (input) => unusedDependencies(input, input.dependencies);
|
|
@@ -12,7 +12,7 @@ import { readsAndWrites } from "./reads-and-writes.js";
|
|
|
12
12
|
import { selfCheck } from "./self-check.js";
|
|
13
13
|
import { fallenMembers, unusedDeclarations } from "./unused-declarations.js";
|
|
14
14
|
import { visibilityNarrowing } from "./visibility-narrowing.js";
|
|
15
|
-
/** Every
|
|
15
|
+
/** Every emitter this analyzer runs, by the name its tests select it by. */
|
|
16
16
|
export const EMITTERS = new Map([
|
|
17
17
|
["unused-declarations", unusedDeclarations],
|
|
18
18
|
["visibility-narrowing", visibilityNarrowing],
|
|
@@ -51,7 +51,7 @@ function markupKeys(input) {
|
|
|
51
51
|
.filter((symbol) => live.has(symbol.parent))
|
|
52
52
|
.map((symbol) => declarationKey(symbol.ref, symbol.position.path)));
|
|
53
53
|
}
|
|
54
|
-
/** Every
|
|
54
|
+
/** Every emitter's findings over one sweep, and those of any further emitter, completed by one step. */
|
|
55
55
|
function completedOver(input, ...more) {
|
|
56
56
|
return completed(input, [...EMITTERS.values(), ...more].flatMap((emit) => emit(input)));
|
|
57
57
|
}
|
|
@@ -70,8 +70,8 @@ function dialsOver(input, found, suppressed, unmarked) {
|
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
72
|
* Every finding of one run swept under its suppressions' marks, decided in one pass: each
|
|
73
|
-
*
|
|
74
|
-
* finding each record claims withheld, the rest withheld by the dials, so a root one
|
|
73
|
+
* emitter's findings completed by one step, so every component number is minted once, the
|
|
74
|
+
* finding each record claims withheld, the rest withheld by the dials, so a root one emitter
|
|
75
75
|
* reports withholds what another reports in its component, and every declared edge
|
|
76
76
|
* evaluated over what remains, so a pending finding is in its evaluation alone.
|
|
77
77
|
*/
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { byPosition } from "../position.js";
|
|
2
|
-
const UNUSED_INTERFACE = "DS1201";
|
|
3
|
-
const UNCALLED_INTERFACE_METHOD = "DS1203";
|
|
4
3
|
/** What each finding says, by what the sweep found about the subject's references. */
|
|
5
4
|
const UNUSED_MESSAGE = "nothing in the target names the interface as a type";
|
|
6
5
|
const UNUSED_DEAD_MESSAGE = "the interface is named as a type only from declarations that are themselves dead";
|
|
@@ -45,7 +44,7 @@ function findingOf(code, symbol, message, implementations) {
|
|
|
45
44
|
}
|
|
46
45
|
/**
|
|
47
46
|
* The findings of the interfaces family, `DS1200` to `DS1299`: `DS1201`, a dead
|
|
48
|
-
* interface, whose members fall with it unreported; and `
|
|
47
|
+
* interface, whose members fall with it unreported; and `DS1202`, a method of a live
|
|
49
48
|
* interface no reference names, unless it is a marker, a method whose every
|
|
50
49
|
* implementation has an empty body. A test file's declaration is neither kind's subject,
|
|
51
50
|
* because a production sweep counts none of the references it can have, save an interface
|
|
@@ -60,7 +59,7 @@ export const interfaces = (input) => {
|
|
|
60
59
|
continue;
|
|
61
60
|
}
|
|
62
61
|
if (symbol.kind === "interface") {
|
|
63
|
-
found.push(findingOf(
|
|
62
|
+
found.push(findingOf(CODE.unusedInterface, symbol, unusedMessage(candidate), run.implementationsOf(candidate.id)));
|
|
64
63
|
continue;
|
|
65
64
|
}
|
|
66
65
|
if (symbol.kind !== "interface-method" ||
|
|
@@ -69,7 +68,7 @@ export const interfaces = (input) => {
|
|
|
69
68
|
marker(input, candidate.id)) {
|
|
70
69
|
continue;
|
|
71
70
|
}
|
|
72
|
-
found.push(findingOf(
|
|
71
|
+
found.push(findingOf(CODE.uncalledInterfaceMethod, symbol, UNCALLED_MESSAGE, run.implementationsOf(symbol.parent)));
|
|
73
72
|
}
|
|
74
73
|
return found;
|
|
75
74
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { KINDS } from "../kinds.js";
|
|
2
3
|
import { parameterRef } from "../ref.js";
|
|
3
|
-
import {
|
|
4
|
+
import {} from "../intra-function-parts.js";
|
|
4
5
|
import { reachedWithTheTests } from "../sweep.js";
|
|
5
6
|
/** A list of rules as a sentence names them. */
|
|
6
7
|
function spelled(rules) {
|
|
@@ -62,9 +63,9 @@ function reported(input, part, callersUnknown) {
|
|
|
62
63
|
}
|
|
63
64
|
const { free, freeButValued, discardedEverywhere } = input.intraFunction;
|
|
64
65
|
switch (part.code) {
|
|
65
|
-
case
|
|
66
|
+
case CODE.unusedParameter:
|
|
66
67
|
return parameterVerdict(part, free, freeButValued) !== undefined;
|
|
67
|
-
case
|
|
68
|
+
case CODE.unusedResult:
|
|
68
69
|
return (free.has(part.declaration) &&
|
|
69
70
|
discardedEverywhere.has(part.declaration) &&
|
|
70
71
|
!callersUnknown.has(part.declaration));
|
|
@@ -73,7 +74,7 @@ function reported(input, part, callersUnknown) {
|
|
|
73
74
|
}
|
|
74
75
|
}
|
|
75
76
|
/**
|
|
76
|
-
* The findings of the
|
|
77
|
+
* The findings of the inside-functions family, `DS1401` to `DS1406`, each about a part of
|
|
77
78
|
* the declaration its reference names, at the part's own position, whatever the sweep
|
|
78
79
|
* decided about a production declaration. A part of test code is reported only where the
|
|
79
80
|
* run that counts test references reaches its declaration and that is no test of dead
|
|
@@ -114,11 +115,11 @@ export const intraFunction = (input) => {
|
|
|
114
115
|
const found = [];
|
|
115
116
|
for (const part of input.intraFunction.parts) {
|
|
116
117
|
const declaration = byId.get(part.declaration);
|
|
117
|
-
const overlap = KINDS.get(part.code)?.overlap ?? [];
|
|
118
|
+
const overlap = KINDS.get(part.code)?.overlap?.ts ?? [];
|
|
118
119
|
if (declaration === undefined || !judged(declaration.id) || !reported(input, part, unknown)) {
|
|
119
120
|
continue;
|
|
120
121
|
}
|
|
121
|
-
const verdict = part.code ===
|
|
122
|
+
const verdict = part.code === CODE.unusedParameter
|
|
122
123
|
? parameterVerdict(part, input.intraFunction.free, input.intraFunction.freeButValued)
|
|
123
124
|
: undefined;
|
|
124
125
|
const message = verdict?.fix === "rename"
|
|
@@ -128,7 +129,7 @@ export const intraFunction = (input) => {
|
|
|
128
129
|
code: part.code,
|
|
129
130
|
position: part.position,
|
|
130
131
|
symbol: {
|
|
131
|
-
...(part.code ===
|
|
132
|
+
...(part.code === CODE.unusedParameter
|
|
132
133
|
? { ref: parameterRef(declaration.ref, part.name), holder: declaration.ref }
|
|
133
134
|
: { ref: declaration.ref }),
|
|
134
135
|
kind: part.kind,
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
const FILE_NEVER_IMPORTED = "DS1502";
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
3
2
|
/** The subject kind of a finding about a source file, from the finding schema's vocabulary. */
|
|
4
3
|
const FILE_SUBJECT = "file";
|
|
5
4
|
/** A file's subject starts at its first character. */
|
|
@@ -40,7 +39,7 @@ function fileNeverBuilt({ config, swept, files }) {
|
|
|
40
39
|
const message = `no project of the build matrix includes this file (${swept.matrix.configurations.join(", ")})`;
|
|
41
40
|
return files.tree
|
|
42
41
|
.filter((file) => !built.has(file.path))
|
|
43
|
-
.map((file) => fileFinding(
|
|
42
|
+
.map((file) => fileFinding(CODE.fileNeverBuilt, file, message));
|
|
44
43
|
}
|
|
45
44
|
/**
|
|
46
45
|
* The paths of the files a reference from a live declaration of another file reaches, a
|
|
@@ -125,13 +124,13 @@ function fileNeverImported(input) {
|
|
|
125
124
|
const file = { path: symbol.position.path, ref: symbol.ref, endLine: symbol.endLine };
|
|
126
125
|
return referenced.has(symbol.position.path)
|
|
127
126
|
? {
|
|
128
|
-
...fileFinding(
|
|
127
|
+
...fileFinding(CODE.fileNeverImported, file, "only code that is itself dead imports this file, and no root names it or a declaration in it"),
|
|
129
128
|
unreachableOnly: true,
|
|
130
129
|
}
|
|
131
|
-
: fileFinding(
|
|
130
|
+
: fileFinding(CODE.fileNeverImported, file, "no import reaches this file and no root names it or a declaration in it");
|
|
132
131
|
});
|
|
133
132
|
}
|
|
134
|
-
/** The findings of the
|
|
133
|
+
/** The findings of the files family, `DS1600` to `DS1699`. */
|
|
135
134
|
export const nonCodeArtifacts = (input) => [
|
|
136
135
|
...fileNeverBuilt(input),
|
|
137
136
|
...fileNeverImported(input),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { positionKey } from "../position.js";
|
|
2
3
|
import { declarationKey } from "../ref.js";
|
|
3
|
-
/** The containers whose type parameters `
|
|
4
|
+
/** The containers whose type parameters `DS1006` reports: a function, a class method and a type alias. */
|
|
4
5
|
const SIGNATURES = new Set(["function", "method", "type"]);
|
|
5
6
|
function indexed(input) {
|
|
6
7
|
const { matrix, sweep } = input.swept;
|
|
@@ -133,7 +134,7 @@ function writeOnlySymbols(run) {
|
|
|
133
134
|
run.candidates.has(symbol.id)) {
|
|
134
135
|
continue;
|
|
135
136
|
}
|
|
136
|
-
found.push(findingAbout(symbol,
|
|
137
|
+
found.push(findingAbout(symbol, CODE.writeOnlySymbol, writeOnlyMessage(run, namedBy, symbol, held), {
|
|
137
138
|
writePositions: held.writes,
|
|
138
139
|
}));
|
|
139
140
|
}
|
|
@@ -157,15 +158,15 @@ function unnamed(run, kind) {
|
|
|
157
158
|
});
|
|
158
159
|
}
|
|
159
160
|
/**
|
|
160
|
-
* `
|
|
161
|
+
* `DS1005`: a member of an enum declaration that nothing names. A member an enum-group
|
|
161
162
|
* record holds back is no candidate, so a member a conversion can produce never reaches
|
|
162
163
|
* this kind.
|
|
163
164
|
*/
|
|
164
165
|
function unusedEnumMembers(run) {
|
|
165
|
-
return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol,
|
|
166
|
+
return unnamed(run, "enum-member").map((symbol) => findingAbout(symbol, CODE.unusedEnumMember, `enum member ${symbol.name} is named nowhere`));
|
|
166
167
|
}
|
|
167
168
|
/**
|
|
168
|
-
* `
|
|
169
|
+
* `DS1006`: a type parameter of a function, a class method or a type alias that neither
|
|
169
170
|
* the declaration's signature nor its body names. An alias names no type of its own, so
|
|
170
171
|
* a parameter its type never names makes no two instantiations distinct. One of a class,
|
|
171
172
|
* an interface or a method signature is never reported: a class or an interface merges
|
|
@@ -174,7 +175,7 @@ function unusedEnumMembers(run) {
|
|
|
174
175
|
function unusedTypeParameters(run) {
|
|
175
176
|
return unnamed(run, "type-parameter")
|
|
176
177
|
.filter((symbol) => SIGNATURES.has(run.symbols.get(symbol.parent)?.kind ?? ""))
|
|
177
|
-
.map((symbol) => findingAbout(symbol,
|
|
178
|
+
.map((symbol) => findingAbout(symbol, CODE.unusedTypeParameter, `type parameter ${symbol.name} is named in neither its signature nor its body`));
|
|
178
179
|
}
|
|
179
180
|
/**
|
|
180
181
|
* The keys of the declarations the write-only kind reports, whatever the
|
|
@@ -185,8 +186,8 @@ export function writeOnlyDeclarations(input) {
|
|
|
185
186
|
return new Set(writeOnlySymbols(indexed(input)).map((finding) => declarationKey(finding.symbol.ref, finding.position.path)));
|
|
186
187
|
}
|
|
187
188
|
/**
|
|
188
|
-
* The findings of the reads-and-writes
|
|
189
|
-
* each code's in site order.
|
|
189
|
+
* The findings of the reads-and-writes kinds, `DS1301`, `DS1005` and `DS1006`, in that
|
|
190
|
+
* order and each code's in site order.
|
|
190
191
|
*/
|
|
191
192
|
export const readsAndWrites = (input) => {
|
|
192
193
|
const run = indexed(input);
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.js";
|
|
1
2
|
import { REPOSITORY_DOCUMENT } from "../config.js";
|
|
2
3
|
import { FIXED_SEVERITY_CODES } from "../kinds.js";
|
|
3
|
-
import { isDependencyCode, isUnsuppressibleCode,
|
|
4
|
-
/** The code a configured root that matches nothing is reported under. */
|
|
5
|
-
const UNMATCHED_ROOT = "DS1704";
|
|
6
|
-
/** The code a configured declaration that names nothing is reported under. */
|
|
7
|
-
const UNMATCHED_DECLARATION = "DS1706";
|
|
4
|
+
import { isDependencyCode, isUnsuppressibleCode, } from "../suppress.js";
|
|
8
5
|
/** The subject kind of a finding about a configured declaration. */
|
|
9
6
|
const DECLARATION_SUBJECT = "configured-declaration";
|
|
10
7
|
/** The subject kind of a finding about a suppression record. */
|
|
@@ -63,7 +60,7 @@ function suppressionRef(symbol, path, files) {
|
|
|
63
60
|
}
|
|
64
61
|
/** One finding per refused suppression: the grammar's reason refusal and its scope refusal. */
|
|
65
62
|
function refusedSuppressions(refusals, files) {
|
|
66
|
-
return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported ===
|
|
63
|
+
return refusals.map((refused) => aboutSuppression(refused.reported, suppressionRef(refused.symbol, refused.path, files), refused.site, `${WRITTEN[refused.mechanism]} for ${refused.code} ${refused.reported === CODE.suppressionWithoutReason
|
|
67
64
|
? "carries no reason"
|
|
68
65
|
: "names a symbol and no path"}`, { mechanism: refused.mechanism, entry: writtenEntry(refused) }));
|
|
69
66
|
}
|
|
@@ -112,7 +109,7 @@ export function staleSuppressions(stale, files) {
|
|
|
112
109
|
? ""
|
|
113
110
|
: `, and ${declared}`;
|
|
114
111
|
return {
|
|
115
|
-
code:
|
|
112
|
+
code: CODE.staleSuppression,
|
|
116
113
|
mechanism: first.mechanism,
|
|
117
114
|
entry: {
|
|
118
115
|
code: first.code,
|
|
@@ -141,7 +138,7 @@ function documentPosition(document) {
|
|
|
141
138
|
*/
|
|
142
139
|
function unmatchedDeclarationFindings(unmatched) {
|
|
143
140
|
return unmatched.map((one) => ({
|
|
144
|
-
code:
|
|
141
|
+
code: CODE.unmatchedConfiguredDeclaration,
|
|
145
142
|
position: documentPosition(one.document),
|
|
146
143
|
symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
|
|
147
144
|
message: `${one.key} entry names no declaration in any project`,
|
|
@@ -157,7 +154,7 @@ function unmatchedDeclarationFindings(unmatched) {
|
|
|
157
154
|
export function unmatchedRootFindings(sources, document) {
|
|
158
155
|
const position = documentPosition(document);
|
|
159
156
|
return sources.map((source) => ({
|
|
160
|
-
code:
|
|
157
|
+
code: CODE.unmatchedRoot,
|
|
161
158
|
position,
|
|
162
159
|
symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
|
|
163
160
|
message: source.includes("*") || source.includes("?")
|
|
@@ -166,7 +163,7 @@ export function unmatchedRootFindings(sources, document) {
|
|
|
166
163
|
}));
|
|
167
164
|
}
|
|
168
165
|
/**
|
|
169
|
-
* The findings of the
|
|
166
|
+
* The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
|
|
170
167
|
* carrying no reason or naming no path, and a configured root or declaration that named
|
|
171
168
|
* nothing. A
|
|
172
169
|
* suppression that matched nothing is a record of the report's stale suppressions, which
|