@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,3 +1,4 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.ts";
|
|
1
2
|
import { REPOSITORY_DOCUMENT } from "../config.ts";
|
|
2
3
|
import type { Finding, FindingDetails, SuppressionEntry } from "../finding.ts";
|
|
3
4
|
import type { InventorySymbol } from "../inventory.ts";
|
|
@@ -6,20 +7,12 @@ import type { Position } from "../position.ts";
|
|
|
6
7
|
import {
|
|
7
8
|
isDependencyCode,
|
|
8
9
|
isUnsuppressibleCode,
|
|
9
|
-
STALE_SUPPRESSION,
|
|
10
|
-
SUPPRESSION_WITHOUT_REASON,
|
|
11
10
|
type Mechanism,
|
|
12
11
|
type Refusal,
|
|
13
12
|
type SuppressionRecord,
|
|
14
13
|
} from "../suppress.ts";
|
|
15
14
|
import type { Emitter } from "./emitter.ts";
|
|
16
15
|
|
|
17
|
-
/** The code a configured root that matches nothing is reported under. */
|
|
18
|
-
const UNMATCHED_ROOT = "DS1704";
|
|
19
|
-
|
|
20
|
-
/** The code a configured declaration that names nothing is reported under. */
|
|
21
|
-
const UNMATCHED_DECLARATION = "DS1706";
|
|
22
|
-
|
|
23
16
|
/** The subject kind of a finding about a configured declaration. */
|
|
24
17
|
const DECLARATION_SUBJECT = "configured-declaration";
|
|
25
18
|
|
|
@@ -39,7 +32,7 @@ export interface StaleRecord {
|
|
|
39
32
|
readonly reports: readonly string[];
|
|
40
33
|
}
|
|
41
34
|
|
|
42
|
-
/** What the
|
|
35
|
+
/** What the configuration family reads: the run's refused suppressions and its configured roots. */
|
|
43
36
|
export interface SelfCheckFacts {
|
|
44
37
|
/** The suppressions the grammar refused with a finding, in reading order. */
|
|
45
38
|
readonly refusals: readonly Refusal[];
|
|
@@ -135,7 +128,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
|
|
|
135
128
|
suppressionRef(refused.symbol, refused.path, files),
|
|
136
129
|
refused.site,
|
|
137
130
|
`${WRITTEN[refused.mechanism]} for ${refused.code} ${
|
|
138
|
-
refused.reported ===
|
|
131
|
+
refused.reported === CODE.suppressionWithoutReason
|
|
139
132
|
? "carries no reason"
|
|
140
133
|
: "names a symbol and no path"
|
|
141
134
|
}`,
|
|
@@ -146,7 +139,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
|
|
|
146
139
|
|
|
147
140
|
/** One stale suppression as the report's stale-suppression record carries it. */
|
|
148
141
|
export interface StaleSuppression {
|
|
149
|
-
readonly code: typeof
|
|
142
|
+
readonly code: typeof CODE.staleSuppression;
|
|
150
143
|
readonly mechanism: Mechanism;
|
|
151
144
|
readonly entry: {
|
|
152
145
|
readonly code: string;
|
|
@@ -209,7 +202,7 @@ export function staleSuppressions(
|
|
|
209
202
|
? ""
|
|
210
203
|
: `, and ${declared}`;
|
|
211
204
|
return {
|
|
212
|
-
code:
|
|
205
|
+
code: CODE.staleSuppression,
|
|
213
206
|
mechanism: first.mechanism,
|
|
214
207
|
entry: {
|
|
215
208
|
code: first.code,
|
|
@@ -242,7 +235,7 @@ function unmatchedDeclarationFindings(
|
|
|
242
235
|
unmatched: readonly UnmatchedDeclaration[],
|
|
243
236
|
): readonly Finding[] {
|
|
244
237
|
return unmatched.map((one) => ({
|
|
245
|
-
code:
|
|
238
|
+
code: CODE.unmatchedConfiguredDeclaration,
|
|
246
239
|
position: documentPosition(one.document),
|
|
247
240
|
symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
|
|
248
241
|
message: `${one.key} entry names no declaration in any project`,
|
|
@@ -262,7 +255,7 @@ export function unmatchedRootFindings(
|
|
|
262
255
|
): readonly Finding[] {
|
|
263
256
|
const position = documentPosition(document);
|
|
264
257
|
return sources.map((source) => ({
|
|
265
|
-
code:
|
|
258
|
+
code: CODE.unmatchedRoot,
|
|
266
259
|
position,
|
|
267
260
|
symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
|
|
268
261
|
message:
|
|
@@ -273,7 +266,7 @@ export function unmatchedRootFindings(
|
|
|
273
266
|
}
|
|
274
267
|
|
|
275
268
|
/**
|
|
276
|
-
* The findings of the
|
|
269
|
+
* The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
|
|
277
270
|
* carrying no reason or naming no path, and a configured root or declaration that named
|
|
278
271
|
* nothing. A
|
|
279
272
|
* suppression that matched nothing is a record of the report's stale suppressions, which
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.ts";
|
|
1
2
|
import type { Finding } from "../finding.ts";
|
|
2
3
|
import type { InventorySymbol, SymbolKind } from "../inventory.ts";
|
|
3
4
|
import type { MatrixCandidate } from "../matrix.ts";
|
|
@@ -14,18 +15,18 @@ const MEMBERS: ReadonlySet<SymbolKind> = new Set([
|
|
|
14
15
|
]);
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
|
-
* The kinds of declaration no code of this
|
|
18
|
+
* The kinds of declaration no code of this emitter reports: an interface and a method an
|
|
18
19
|
* interface declares are the interface kinds' subjects, and a type parameter is the
|
|
19
20
|
* subject of the unused-type-parameter kind or of none.
|
|
20
21
|
*/
|
|
21
|
-
const
|
|
22
|
+
const NOT_REPORTED_HERE: ReadonlySet<SymbolKind> = new Set([
|
|
22
23
|
"file",
|
|
23
24
|
"interface",
|
|
24
25
|
"interface-method",
|
|
25
26
|
"type-parameter",
|
|
26
27
|
]);
|
|
27
28
|
|
|
28
|
-
/** The reader's word for each kind of declaration a finding of
|
|
29
|
+
/** The reader's word for each kind of declaration a finding of this emitter names. */
|
|
29
30
|
const WORDS: Readonly<Record<SymbolKind, string>> = {
|
|
30
31
|
file: "file",
|
|
31
32
|
function: "function",
|
|
@@ -71,9 +72,9 @@ interface Judged {
|
|
|
71
72
|
function codeOf(judged: Judged): string | undefined {
|
|
72
73
|
const { candidate, symbol } = judged;
|
|
73
74
|
if (candidate.testOfDeadCode) {
|
|
74
|
-
return judged.testsUnseenAPI ? undefined :
|
|
75
|
+
return judged.testsUnseenAPI ? undefined : CODE.testOfDeadCode;
|
|
75
76
|
}
|
|
76
|
-
if ((judged.test && !candidate.unreferencedTest) ||
|
|
77
|
+
if ((judged.test && !candidate.unreferencedTest) || NOT_REPORTED_HERE.has(symbol.kind)) {
|
|
77
78
|
return undefined;
|
|
78
79
|
}
|
|
79
80
|
const referenced = candidate.productionRefs + candidate.testRefs > 0;
|
|
@@ -84,33 +85,33 @@ function codeOf(judged: Judged): string | undefined {
|
|
|
84
85
|
return unreferencedCode(symbol);
|
|
85
86
|
}
|
|
86
87
|
if (candidate.heldByTests === candidate.id) {
|
|
87
|
-
return
|
|
88
|
+
return CODE.testOnlyUse;
|
|
88
89
|
}
|
|
89
90
|
if (candidate.productionRefs === 0 && judged.deprecated) {
|
|
90
|
-
return
|
|
91
|
+
return CODE.deprecatedUnused;
|
|
91
92
|
}
|
|
92
93
|
if (
|
|
93
94
|
candidate.testRefs > 0 &&
|
|
94
95
|
(candidate.productionRefs === 0 ||
|
|
95
96
|
(candidate.relation === "reachability" && candidate.keptByTests))
|
|
96
97
|
) {
|
|
97
|
-
return
|
|
98
|
+
return CODE.testOnlyUse;
|
|
98
99
|
}
|
|
99
100
|
if (MEMBERS.has(symbol.kind)) {
|
|
100
|
-
return
|
|
101
|
+
return CODE.unusedMember;
|
|
101
102
|
}
|
|
102
103
|
if (!symbol.exported) {
|
|
103
|
-
return
|
|
104
|
+
return CODE.unusedUnexported;
|
|
104
105
|
}
|
|
105
|
-
return judged.unreachable ? undefined :
|
|
106
|
+
return judged.unreachable ? undefined : CODE.unusedExported;
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
/** The code a declaration nothing references carries, by its shape and its visibility. */
|
|
109
110
|
function unreferencedCode(symbol: InventorySymbol): string {
|
|
110
111
|
if (MEMBERS.has(symbol.kind)) {
|
|
111
|
-
return
|
|
112
|
+
return CODE.unusedMember;
|
|
112
113
|
}
|
|
113
|
-
return symbol.exported ?
|
|
114
|
+
return symbol.exported ? CODE.unusedExported : CODE.unusedUnexported;
|
|
114
115
|
}
|
|
115
116
|
|
|
116
117
|
/** The visibility a member's message names, where it narrows the member's reach. */
|
|
@@ -135,17 +136,17 @@ function messageOf(code: string, judged: Judged): string {
|
|
|
135
136
|
const { candidate, symbol } = judged;
|
|
136
137
|
const word = WORDS[symbol.kind];
|
|
137
138
|
switch (code) {
|
|
138
|
-
case
|
|
139
|
+
case CODE.testOfDeadCode:
|
|
139
140
|
return TEST_OF_DEAD_CODE;
|
|
140
|
-
case
|
|
141
|
+
case CODE.deprecatedUnused:
|
|
141
142
|
return `deprecated ${word} has no production reference`;
|
|
142
|
-
case
|
|
143
|
+
case CODE.testOnlyUse:
|
|
143
144
|
return candidate.productionRefs === 0
|
|
144
145
|
? `${word} is referenced only from test files and never from production code`
|
|
145
146
|
: `${word} is referenced only from test files and from declarations that are themselves dead`;
|
|
146
147
|
}
|
|
147
148
|
const subject =
|
|
148
|
-
code ===
|
|
149
|
+
code === CODE.unusedMember
|
|
149
150
|
? `${visibilityWord(symbol)}${word}`
|
|
150
151
|
: symbol.kind === "export-alias"
|
|
151
152
|
? word
|
|
@@ -153,7 +154,7 @@ function messageOf(code: string, judged: Judged): string {
|
|
|
153
154
|
if (candidate.relation === "reachability") {
|
|
154
155
|
return `${subject} is referenced only from declarations that are themselves dead`;
|
|
155
156
|
}
|
|
156
|
-
if (code ===
|
|
157
|
+
if (code === CODE.unusedExported) {
|
|
157
158
|
return `${subject} has no reference in the target and none from any loaded consumer`;
|
|
158
159
|
}
|
|
159
160
|
return `${subject} has no reference in the target`;
|
|
@@ -205,15 +206,15 @@ function brandMembers(input: EmitterInput): ReadonlySet<string> {
|
|
|
205
206
|
/** The kinds of member a brand is: a data member of a type or of a class. */
|
|
206
207
|
const BRANDS: ReadonlySet<SymbolKind> = new Set(["type-member", "class-member"]);
|
|
207
208
|
|
|
208
|
-
/** The findings of the unused-
|
|
209
|
+
/** The findings of the unused-declaration kinds, `DS1001` to `DS1004` and `DS1102` to `DS1104`. */
|
|
209
210
|
export const unusedDeclarations: Emitter = (input) => [
|
|
210
|
-
...
|
|
211
|
+
...emitterFindings(input, false),
|
|
211
212
|
...unusedImports(input),
|
|
212
213
|
];
|
|
213
214
|
|
|
214
215
|
/**
|
|
215
|
-
* The import bindings their file never reads
|
|
216
|
-
*
|
|
216
|
+
* The import bindings their file never reads. A generated file's are the generator's to
|
|
217
|
+
* remove unless the run includes generated files.
|
|
217
218
|
*/
|
|
218
219
|
function unusedImports(input: EmitterInput): Finding[] {
|
|
219
220
|
const generated =
|
|
@@ -223,7 +224,7 @@ function unusedImports(input: EmitterInput): Finding[] {
|
|
|
223
224
|
? []
|
|
224
225
|
: [
|
|
225
226
|
{
|
|
226
|
-
code:
|
|
227
|
+
code: CODE.unusedImport,
|
|
227
228
|
position: binding.position,
|
|
228
229
|
symbol: { ref: binding.ref, kind: "import", name: binding.name, sizeLines: 1 },
|
|
229
230
|
message: `import binding ${binding.name} is never read in its file`,
|
|
@@ -237,10 +238,10 @@ function unusedImports(input: EmitterInput): Finding[] {
|
|
|
237
238
|
* a record on such a member is matched against, since the report carries the container's
|
|
238
239
|
* finding rather than one of the member's own.
|
|
239
240
|
*/
|
|
240
|
-
export const fallenMembers: Emitter = (input) =>
|
|
241
|
+
export const fallenMembers: Emitter = (input) => emitterFindings(input, true);
|
|
241
242
|
|
|
242
|
-
/**
|
|
243
|
-
function
|
|
243
|
+
/** This emitter's findings, or, where `fallen` is set, its dead containers' members' alone. */
|
|
244
|
+
function emitterFindings(input: EmitterInput, fallen: boolean): Finding[] {
|
|
244
245
|
const union = input.swept.matrix.union;
|
|
245
246
|
const dead = new Set(input.swept.sweep.candidates.map((candidate) => candidate.id));
|
|
246
247
|
const unreachable = unreachableExports(input);
|
|
@@ -269,7 +270,7 @@ function familyFindings(input: EmitterInput, fallen: boolean): Finding[] {
|
|
|
269
270
|
const code = codeOf(judged);
|
|
270
271
|
if (
|
|
271
272
|
code === undefined ||
|
|
272
|
-
(code ===
|
|
273
|
+
(code === CODE.unusedMember && (brands ??= brandMembers(input)).has(symbol.id))
|
|
273
274
|
) {
|
|
274
275
|
continue;
|
|
275
276
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.ts";
|
|
1
2
|
import type { Finding } from "../finding.ts";
|
|
2
3
|
import { OUTSIDE, type Graph } from "../graph.ts";
|
|
3
4
|
import type { InventorySymbol, SymbolKind } from "../inventory.ts";
|
|
@@ -8,10 +9,6 @@ import { runnerCalls } from "../sweep.ts";
|
|
|
8
9
|
import type { Emitter, EmitterInput } from "./emitter.ts";
|
|
9
10
|
import { writeOnlyDeclarations } from "./reads-and-writes.ts";
|
|
10
11
|
|
|
11
|
-
const UNNECESSARY_EXPORT = "DS1101";
|
|
12
|
-
const UNREACHABLE_EXPORT = "DS1103";
|
|
13
|
-
const REDUNDANT_EXPORT_KEYWORD = "DS1104";
|
|
14
|
-
|
|
15
12
|
/** How far the references to one declaration reach, from the narrowest. */
|
|
16
13
|
type Reach = "file" | "package" | "outside";
|
|
17
14
|
|
|
@@ -22,7 +19,7 @@ type Reach = "file" | "package" | "outside";
|
|
|
22
19
|
*/
|
|
23
20
|
const PUBLISHING: ReadonlySet<RootKind> = new Set<RootKind>(["manifest-entry", "published-api"]);
|
|
24
21
|
|
|
25
|
-
/** The reader's word for each kind of declaration this
|
|
22
|
+
/** The reader's word for each kind of declaration this emitter reports. */
|
|
26
23
|
const WORDS: Partial<Readonly<Record<SymbolKind, string>>> = {
|
|
27
24
|
function: "function",
|
|
28
25
|
class: "class",
|
|
@@ -151,8 +148,8 @@ function wordOf(symbol: InventorySymbol): string {
|
|
|
151
148
|
|
|
152
149
|
/** The visibility each narrowing code names, which only the narrowing codes carry. */
|
|
153
150
|
const NARROWER: Readonly<Record<string, "file" | "package">> = {
|
|
154
|
-
[
|
|
155
|
-
[
|
|
151
|
+
[CODE.redundantExportKeyword]: "file",
|
|
152
|
+
[CODE.unnecessaryExport]: "package",
|
|
156
153
|
};
|
|
157
154
|
|
|
158
155
|
function findingOf(symbol: InventorySymbol, code: string, message: string): Finding {
|
|
@@ -206,7 +203,7 @@ function narrowing(
|
|
|
206
203
|
}
|
|
207
204
|
return findingOf(
|
|
208
205
|
symbol,
|
|
209
|
-
|
|
206
|
+
CODE.redundantExportKeyword,
|
|
210
207
|
`exported ${word} is referenced only inside the file that declares it`,
|
|
211
208
|
);
|
|
212
209
|
case "package":
|
|
@@ -215,7 +212,7 @@ function narrowing(
|
|
|
215
212
|
}
|
|
216
213
|
return findingOf(
|
|
217
214
|
symbol,
|
|
218
|
-
|
|
215
|
+
CODE.unnecessaryExport,
|
|
219
216
|
`exported ${word} is referenced only inside the package that declares it`,
|
|
220
217
|
);
|
|
221
218
|
default:
|
|
@@ -254,13 +251,13 @@ function unreachable(
|
|
|
254
251
|
: "has no reference in the target";
|
|
255
252
|
return findingOf(
|
|
256
253
|
symbol,
|
|
257
|
-
|
|
254
|
+
CODE.unreachableExport,
|
|
258
255
|
`exported ${wordOf(symbol)} ${found}, and nothing outside can import the file that declares it`,
|
|
259
256
|
);
|
|
260
257
|
}
|
|
261
258
|
|
|
262
259
|
/**
|
|
263
|
-
* The visibility-narrowing
|
|
260
|
+
* The visibility-narrowing kinds over one run: `DS1501`, `DS1101` and `DS1503`. A finding
|
|
264
261
|
* about a symbol a declared cross-language edge names is reported here like any other, and
|
|
265
262
|
* the edge's evaluation then holds it pending, because the edge stands for a reference from
|
|
266
263
|
* outside the file and the package whose use is decided in the other language. A
|
|
@@ -316,5 +313,5 @@ export function unreachableExports(input: EmitterInput): ReadonlySet<string> {
|
|
|
316
313
|
return found;
|
|
317
314
|
}
|
|
318
315
|
|
|
319
|
-
/** The findings of the visibility-narrowing
|
|
316
|
+
/** The findings of the visibility-narrowing kinds, `DS1501`, `DS1101` and `DS1503`. */
|
|
320
317
|
export const visibilityNarrowing: Emitter = narrowings;
|
package/src/findings-pass.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
* verdict a report carries beside them.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
+
import { EXIT_CLEAN, EXIT_FINDINGS, EXIT_PENDING } from "./contract/contract.generated.ts";
|
|
7
8
|
import type { AnalysisInputs } from "./analysis.ts";
|
|
8
9
|
import { fails, type Config } from "./config.ts";
|
|
9
10
|
import type { EdgeEvaluation } from "./edges.ts";
|
|
@@ -23,7 +24,6 @@ import {
|
|
|
23
24
|
type Ledger,
|
|
24
25
|
} from "./suppress.ts";
|
|
25
26
|
import type { Provenance, Recorded } from "./suppress-file.ts";
|
|
26
|
-
import { EXIT_CLEAN, EXIT_FINDINGS } from "./verbs/verb.ts";
|
|
27
27
|
|
|
28
28
|
/** The counts a report's totals carry beside its findings. */
|
|
29
29
|
interface PassTotals {
|
|
@@ -49,9 +49,6 @@ export interface PassResult {
|
|
|
49
49
|
readonly ledger: Ledger;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
/** The exit code of a report holding at least one pending finding. */
|
|
53
|
-
export const EXIT_PENDING = 4;
|
|
54
|
-
|
|
55
52
|
/** Two strings ordered bytewise. */
|
|
56
53
|
function compare(a: string, b: string): number {
|
|
57
54
|
if (a === b) {
|
package/src/index.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* write to a local that no read reaches, and each case an earlier case covers.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { CODE } from "./contract/contract.generated.ts";
|
|
8
9
|
import {
|
|
9
10
|
isArrowFunction,
|
|
10
11
|
isAwaitExpression,
|
|
@@ -179,13 +180,6 @@ export interface ProjectParts {
|
|
|
179
180
|
readonly constructions: ReadonlySet<string>;
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
/** The codes of the parts this module reads. */
|
|
183
|
-
export const UNUSED_PARAMETER = "DS1801";
|
|
184
|
-
export const UNUSED_RESULT = "DS1803";
|
|
185
|
-
const UNREACHABLE_STATEMENT = "DS1805";
|
|
186
|
-
const DEAD_STORE = "DS1807";
|
|
187
|
-
const UNREACHABLE_CASE = "DS1809";
|
|
188
|
-
|
|
189
183
|
/** The result types that carry no value, as the checker spells them. */
|
|
190
184
|
const NO_VALUE: ReadonlySet<string> = new Set([
|
|
191
185
|
"void",
|
|
@@ -869,7 +863,7 @@ export function projectParts<Brand>(
|
|
|
869
863
|
}
|
|
870
864
|
walk.catches.forEach(({ name, holder }, at) => {
|
|
871
865
|
parts.push({
|
|
872
|
-
code:
|
|
866
|
+
code: CODE.deadStore,
|
|
873
867
|
declaration: holder,
|
|
874
868
|
kind: "store",
|
|
875
869
|
name: name.text,
|
|
@@ -881,7 +875,7 @@ export function projectParts<Brand>(
|
|
|
881
875
|
for (const { names, uses, holder } of loopVariables) {
|
|
882
876
|
for (const name of names) {
|
|
883
877
|
parts.push({
|
|
884
|
-
code:
|
|
878
|
+
code: CODE.deadStore,
|
|
885
879
|
declaration: holder,
|
|
886
880
|
kind: "store",
|
|
887
881
|
name: name.text,
|
|
@@ -899,7 +893,7 @@ export function projectParts<Brand>(
|
|
|
899
893
|
});
|
|
900
894
|
for (const { statement, holder } of walk.unreachable) {
|
|
901
895
|
parts.push({
|
|
902
|
-
code:
|
|
896
|
+
code: CODE.unreachableStatement,
|
|
903
897
|
declaration: holder,
|
|
904
898
|
kind: "statement",
|
|
905
899
|
name: "statement",
|
|
@@ -910,7 +904,7 @@ export function projectParts<Brand>(
|
|
|
910
904
|
}
|
|
911
905
|
for (const { clause, text, holder } of walk.cases) {
|
|
912
906
|
parts.push({
|
|
913
|
-
code:
|
|
907
|
+
code: CODE.unreachableCase,
|
|
914
908
|
declaration: holder,
|
|
915
909
|
kind: "case",
|
|
916
910
|
name: text,
|
|
@@ -1176,7 +1170,7 @@ function parameterParts(
|
|
|
1176
1170
|
return;
|
|
1177
1171
|
}
|
|
1178
1172
|
const part: PartFact = {
|
|
1179
|
-
code:
|
|
1173
|
+
code: CODE.unusedParameter,
|
|
1180
1174
|
declaration,
|
|
1181
1175
|
kind: "parameter",
|
|
1182
1176
|
name: name.text,
|
|
@@ -1353,7 +1347,7 @@ function deadStores(
|
|
|
1353
1347
|
): PartFact[] {
|
|
1354
1348
|
const found: PartFact[] = [];
|
|
1355
1349
|
const deadAt = (local: Local, target: Identifier): PartFact => ({
|
|
1356
|
-
code:
|
|
1350
|
+
code: CODE.deadStore,
|
|
1357
1351
|
declaration: holder,
|
|
1358
1352
|
kind: "store",
|
|
1359
1353
|
name: local.name.text,
|
|
@@ -1482,7 +1476,7 @@ function resultParts<Brand>(
|
|
|
1482
1476
|
const valued = project.queries.nonNullable(result);
|
|
1483
1477
|
const members = isAnswered(valued) ? project.queries.propertiesOf(valued) : UNANSWERED;
|
|
1484
1478
|
found.push({
|
|
1485
|
-
code:
|
|
1479
|
+
code: CODE.unusedResult,
|
|
1486
1480
|
declaration: id,
|
|
1487
1481
|
kind: "result",
|
|
1488
1482
|
name: "result",
|