@cplieger/deadset-ts 8.0.0-dev.2 → 8.0.0-dev.20
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/README.md +3 -1
- package/THIRD_PARTY_NOTICES.md +27 -0
- package/dist/bin/mapper-connection.js +2 -1
- package/dist/bin/node-host.js +24 -5
- package/dist/src/alias-chain.js +2 -7
- package/dist/src/amd.js +81 -0
- package/dist/src/analysis.js +269 -432
- package/dist/src/augmentations.js +64 -3
- package/dist/src/automatic-types.js +10 -29
- package/dist/src/bindings.js +382 -0
- package/dist/src/calls.js +279 -43
- package/dist/src/commands/held.js +499 -0
- package/dist/src/commands/read.js +161 -0
- package/dist/src/commands/shell.js +169 -0
- package/dist/src/commands/tools.js +1847 -0
- package/dist/src/component-files.js +3 -2
- package/dist/src/component-layer.js +4 -2
- package/dist/src/config.js +6 -82
- package/dist/src/conformance-record.js +1 -1
- package/dist/src/consumers.js +10 -38
- package/dist/src/contextual-uses.js +57 -26
- package/dist/src/contract/config.generated.js +561 -0
- package/dist/src/contract/contract.generated.js +1369 -0
- package/dist/src/contract/report.generated.js +866 -0
- package/dist/src/dependencies.js +164 -121
- package/dist/src/destructuring.js +1 -19
- package/dist/src/edges.js +38 -122
- package/dist/src/element-access.js +181 -168
- package/dist/src/entries/build-scripts.js +222 -0
- package/dist/src/{configuration-files.js → entries/configuration-files.js} +52 -256
- package/dist/src/{convention-rows.js → entries/convention-rows.js} +170 -30
- package/dist/src/entries/conventions.js +740 -0
- package/dist/src/{html-entries.js → entries/html-entries.js} +12 -42
- package/dist/src/{mdx-entries.js → entries/mdx-entries.js} +5 -28
- package/dist/src/entries/run-directories.js +77 -0
- package/dist/src/entries/sources.js +144 -0
- package/dist/src/entries/static-module.js +670 -0
- package/dist/src/entries/test-runners.js +650 -0
- package/dist/src/entries/workflow-steps.js +345 -0
- package/dist/src/enum-group.js +3 -10
- package/dist/src/erased-stores.js +4 -6
- package/dist/src/exempt-classes.js +1 -63
- package/dist/src/exempt.js +21 -66
- package/dist/src/exposure.js +400 -0
- package/dist/src/extensions.js +37 -0
- package/dist/src/facts.js +38 -0
- package/dist/src/failure.js +36 -0
- package/dist/src/file-facts.js +3 -26
- package/dist/src/findings/completion.js +109 -56
- package/dist/src/findings/dependencies-and-module-machinery.js +4 -5
- package/dist/src/findings/emitters.js +27 -41
- package/dist/src/{implementations.js → findings/implementations.js} +3 -3
- package/dist/src/{in-operands.js → findings/in-operands.js} +3 -2
- package/dist/src/findings/interfaces.js +4 -5
- package/dist/src/findings/intra-function.js +16 -13
- package/dist/src/findings/non-code-artifacts.js +17 -12
- package/dist/src/findings/reads-and-writes.js +86 -27
- package/dist/src/findings/self-check.js +44 -30
- package/dist/src/findings/unused-declarations.js +29 -45
- package/dist/src/findings/visibility-narrowing.js +23 -31
- package/dist/src/findings-pass.js +13 -21
- package/dist/src/framework-lifecycle.js +46 -19
- package/dist/src/fs/document.js +52 -0
- package/dist/src/fs/manifest.js +67 -0
- package/dist/src/fs/tree.js +88 -0
- package/dist/src/generated-file.js +174 -28
- package/dist/src/git-ignore.js +39 -26
- package/dist/src/import-bindings.js +73 -28
- package/dist/src/index/sites.js +557 -0
- package/dist/src/index.js +2 -2
- package/dist/src/indexed-access.js +523 -478
- package/dist/src/injection-container.js +2 -2
- package/dist/src/interface-satisfaction.js +1 -1
- package/dist/src/intra-function-parts.js +63 -43
- package/dist/src/inventory/commonjs.js +507 -0
- package/dist/src/inventory/enumerate.js +167 -0
- package/dist/src/inventory/syntax.js +236 -0
- package/dist/src/inventory.js +323 -724
- package/dist/src/javascript-file.js +48 -0
- package/dist/src/json-document.js +198 -67
- package/dist/src/keyof-comparisons.js +126 -107
- package/dist/src/kinds.js +3 -366
- package/dist/src/{components.js → liveness/components.js} +2 -3
- package/dist/src/{graph.js → liveness/graph.js} +52 -28
- package/dist/src/liveness/matrix.js +99 -0
- package/dist/src/liveness/sweep.js +558 -0
- package/dist/src/load/classify.js +289 -0
- package/dist/src/load/diagnostics.js +87 -0
- package/dist/src/load/discover.js +285 -0
- package/dist/src/{emit-map.js → load/emit-map.js} +1 -1
- package/dist/src/load/expected-module.js +136 -0
- package/dist/src/load/load.js +27 -0
- package/dist/src/load/module-lookup.js +37 -0
- package/dist/src/load/package-scope.js +56 -0
- package/dist/src/load/plan.js +313 -0
- package/dist/src/load/specifiers.js +113 -0
- package/dist/src/load/synthesize.js +152 -0
- package/dist/src/load/test-globals.js +207 -0
- package/dist/src/load/test-joins.js +82 -0
- package/dist/src/{workspace-manifests.js → load/workspace-manifests.js} +4 -4
- package/dist/src/{workspace-programs.js → load/workspace-programs.js} +89 -66
- package/dist/src/{workspace-resolution.js → load/workspace-resolution.js} +24 -66
- package/dist/src/{workspace-run.js → load/workspace-run.js} +7 -7
- package/dist/src/{workspace.js → load/workspace.js} +62 -124
- package/dist/src/module-declarations.js +70 -85
- package/dist/src/overrides.js +134 -112
- package/dist/src/partial.js +2 -1
- package/dist/src/paths.js +82 -16
- package/dist/src/platform-calls.js +78 -0
- package/dist/src/platform-symbols.js +134 -0
- package/dist/src/position.js +43 -1
- package/dist/src/print.js +11 -79
- package/dist/src/product.js +13 -0
- package/dist/src/query.js +47 -0
- package/dist/src/ref.js +12 -20
- package/dist/src/references/read-rule.js +1 -0
- package/dist/src/references/read-rules.js +48 -0
- package/dist/src/references/sink.js +237 -0
- package/dist/src/references/sources.js +450 -0
- package/dist/src/references.js +117 -1074
- package/dist/src/report-schema.js +51 -0
- package/dist/src/report.js +57 -41
- package/dist/src/reporters/annotations.js +15 -8
- package/dist/src/reporters/sarif.js +16 -10
- package/dist/src/reporters/template.js +4 -19
- package/dist/src/resolve.js +246 -730
- package/dist/src/{configured-declarations.js → roots/configured-declarations.js} +22 -24
- package/dist/src/{entry-point-gaps.js → roots/entry-point-gaps.js} +6 -15
- package/dist/src/roots/manifest.js +216 -0
- package/dist/src/roots/published-reach.js +412 -0
- package/dist/src/roots/root-set.js +487 -0
- package/dist/src/roots/unseen-loads.js +236 -0
- package/dist/src/run.js +66 -77
- package/dist/src/schema.js +320 -343
- package/dist/src/scope.js +38 -115
- package/dist/src/serialization-contract.js +601 -22
- package/dist/src/session.js +37 -29
- package/dist/src/source-files.js +6 -10
- package/dist/src/stores.js +4 -2
- package/dist/src/suppress-file.js +25 -28
- package/dist/src/suppress-inline.js +36 -83
- package/dist/src/suppress.js +50 -71
- package/dist/src/symbol-keys.js +92 -88
- package/dist/src/template-field.js +9 -19
- package/dist/src/tests/file-class.js +76 -0
- package/dist/src/{outside-tests.js → tests/outside.js} +7 -7
- package/dist/src/{test-support.js → tests/support.js} +5 -12
- package/dist/src/text/compare.js +26 -0
- package/dist/src/text/glob.js +194 -0
- package/dist/src/text/named-files.js +298 -0
- package/dist/src/text/yaml.js +684 -0
- package/dist/src/type-errors.js +11 -232
- package/dist/src/type-parameter-reads.js +178 -139
- package/dist/src/unimplemented-callees.js +262 -242
- package/dist/src/unwrap.js +23 -0
- package/dist/src/usage.js +10 -0
- package/dist/src/vendor/unbash/ansi-c.js +132 -0
- package/dist/src/vendor/unbash/arithmetic-parts.js +37 -0
- package/dist/src/vendor/unbash/arithmetic.js +591 -0
- package/dist/src/vendor/unbash/assignment.js +131 -0
- package/dist/src/vendor/unbash/chars.js +48 -0
- package/dist/src/vendor/unbash/command.js +41 -0
- package/dist/src/vendor/unbash/expansion.js +80 -0
- package/dist/src/vendor/unbash/glob.js +268 -0
- package/dist/src/vendor/unbash/heredoc.js +27 -0
- package/dist/src/vendor/unbash/internal-types.js +1 -0
- package/dist/src/vendor/unbash/lexer.js +4274 -0
- package/dist/src/vendor/unbash/limits.js +3 -0
- package/dist/src/vendor/unbash/parser.js +1366 -0
- package/dist/src/vendor/unbash/parts.js +57 -0
- package/dist/src/vendor/unbash/substitution-context.js +8 -0
- package/dist/src/vendor/unbash/traversal.js +212 -0
- package/dist/src/vendor/unbash/types.js +1 -0
- package/dist/src/vendor/unbash/word-value.js +61 -0
- package/dist/src/vendor/unbash/word.js +40 -0
- package/dist/src/verbs/analyze.js +194 -127
- package/dist/src/verbs/describe.js +13 -18
- package/dist/src/verbs/explain.js +85 -139
- package/dist/src/verbs/print-config.js +2 -1
- package/dist/src/verbs/print-projects.js +6 -4
- package/dist/src/verbs/print-retained.js +7 -5
- package/dist/src/verbs/print-roots.js +4 -2
- package/dist/src/verbs/verb.js +1 -5
- package/dist/src/verbs/version.js +14 -3
- package/jsr.json +2 -1
- package/package.json +14 -8
- package/src/alias-chain.ts +2 -9
- package/src/amd.ts +130 -0
- package/src/analysis.ts +424 -650
- package/src/augmentations.ts +93 -4
- package/src/automatic-types.ts +12 -30
- package/src/bindings.ts +460 -0
- package/src/calls.ts +338 -46
- package/src/commands/held.ts +632 -0
- package/src/commands/read.ts +242 -0
- package/src/commands/shell.ts +228 -0
- package/src/commands/tools.ts +2382 -0
- package/src/component-files.ts +4 -2
- package/src/component-layer.ts +4 -2
- package/src/config.ts +31 -302
- package/src/conformance-record.ts +1 -1
- package/src/consumers.ts +16 -66
- package/src/contextual-uses.ts +66 -34
- package/src/contract/config.generated.ts +821 -0
- package/src/contract/contract.generated.ts +1452 -0
- package/src/contract/report.generated.ts +1241 -0
- package/src/dependencies.ts +222 -127
- package/src/destructuring.ts +1 -31
- package/src/edges.ts +41 -140
- package/src/element-access.ts +190 -187
- package/src/entries/build-scripts.ts +292 -0
- package/src/{configuration-files.ts → entries/configuration-files.ts} +68 -278
- package/src/{convention-rows.ts → entries/convention-rows.ts} +227 -31
- package/src/{conventions.ts → entries/conventions.ts} +367 -583
- package/src/{html-entries.ts → entries/html-entries.ts} +22 -48
- package/src/{mdx-entries.ts → entries/mdx-entries.ts} +7 -30
- package/src/entries/run-directories.ts +108 -0
- package/src/entries/sources.ts +266 -0
- package/src/entries/static-module.ts +858 -0
- package/src/entries/test-runners.ts +835 -0
- package/src/entries/workflow-steps.ts +432 -0
- package/src/enum-group.ts +2 -11
- package/src/erased-stores.ts +3 -7
- package/src/exempt-classes.ts +1 -75
- package/src/exempt.ts +70 -98
- package/src/exposure.ts +492 -0
- package/src/extensions.ts +45 -0
- package/src/facts.ts +46 -0
- package/src/failure.ts +63 -0
- package/src/file-facts.ts +15 -25
- package/src/finding.ts +10 -10
- package/src/findings/boundary.ts +11 -0
- package/src/findings/completion.ts +133 -64
- package/src/findings/dependencies-and-module-machinery.ts +4 -7
- package/src/findings/emitter.ts +9 -10
- package/src/findings/emitters.ts +38 -52
- package/src/{implementations.ts → findings/implementations.ts} +4 -4
- package/src/{in-operands.ts → findings/in-operands.ts} +4 -3
- package/src/findings/interfaces.ts +7 -9
- package/src/findings/intra-function.ts +16 -14
- package/src/findings/non-code-artifacts.ts +24 -15
- package/src/findings/reads-and-writes.ts +118 -41
- package/src/findings/self-check.ts +51 -38
- package/src/findings/unused-declarations.ts +31 -49
- package/src/findings/visibility-narrowing.ts +36 -40
- package/src/findings-pass.ts +15 -31
- package/src/framework-lifecycle.ts +47 -19
- package/src/fs/document.ts +70 -0
- package/src/fs/manifest.ts +96 -0
- package/src/fs/tree.ts +110 -0
- package/src/generated-file.ts +242 -35
- package/src/git-ignore.ts +50 -26
- package/src/host.ts +12 -5
- package/src/import-bindings.ts +98 -29
- package/src/index/sites.ts +781 -0
- package/src/index.ts +2 -2
- package/src/indexed-access.ts +570 -527
- package/src/injection-container.ts +2 -2
- package/src/interface-satisfaction.ts +2 -2
- package/src/intra-function-parts.ts +73 -44
- package/src/inventory/commonjs.ts +696 -0
- package/src/inventory/enumerate.ts +203 -0
- package/src/inventory/syntax.ts +311 -0
- package/src/inventory.ts +442 -895
- package/src/javascript-file.ts +54 -0
- package/src/json-document.ts +241 -76
- package/src/keyof-comparisons.ts +133 -122
- package/src/kinds.ts +5 -413
- package/src/{components.ts → liveness/components.ts} +4 -6
- package/src/{graph.ts → liveness/graph.ts} +100 -35
- package/src/liveness/matrix.ts +162 -0
- package/src/liveness/sweep.ts +855 -0
- package/src/load/classify.ts +433 -0
- package/src/load/diagnostics.ts +154 -0
- package/src/load/discover.ts +471 -0
- package/src/{emit-map.ts → load/emit-map.ts} +1 -1
- package/src/load/expected-module.ts +194 -0
- package/src/load/load.ts +73 -0
- package/src/load/module-lookup.ts +50 -0
- package/src/load/package-scope.ts +74 -0
- package/src/load/plan.ts +513 -0
- package/src/load/specifiers.ts +171 -0
- package/src/load/synthesize.ts +230 -0
- package/src/load/test-globals.ts +251 -0
- package/src/load/test-joins.ts +98 -0
- package/src/{workspace-manifests.ts → load/workspace-manifests.ts} +5 -5
- package/src/{workspace-programs.ts → load/workspace-programs.ts} +128 -85
- package/src/{workspace-resolution.ts → load/workspace-resolution.ts} +41 -77
- package/src/{workspace-run.ts → load/workspace-run.ts} +18 -16
- package/src/{workspace.ts → load/workspace.ts} +90 -134
- package/src/module-declarations.ts +74 -98
- package/src/overrides.ts +162 -134
- package/src/partial.ts +3 -2
- package/src/paths.ts +92 -16
- package/src/platform-calls.ts +119 -0
- package/src/platform-symbols.ts +189 -0
- package/src/position.ts +44 -1
- package/src/print.ts +12 -92
- package/src/product.ts +18 -0
- package/src/query.ts +92 -0
- package/src/ref.ts +12 -20
- package/src/references/read-rule.ts +60 -0
- package/src/references/read-rules.ts +55 -0
- package/src/references/sink.ts +314 -0
- package/src/references/sources.ts +632 -0
- package/src/references.ts +187 -1450
- package/src/report-schema.ts +68 -0
- package/src/report.ts +103 -226
- package/src/reporters/annotations.ts +22 -11
- package/src/reporters/json.ts +1 -1
- package/src/reporters/reporter.ts +2 -4
- package/src/reporters/reporters.ts +1 -1
- package/src/reporters/sarif.ts +29 -16
- package/src/reporters/template.ts +4 -20
- package/src/reporters/text.ts +3 -3
- package/src/resolve.ts +284 -1115
- package/src/{configured-declarations.ts → roots/configured-declarations.ts} +27 -29
- package/src/{entry-point-gaps.ts → roots/entry-point-gaps.ts} +7 -16
- package/src/roots/manifest.ts +303 -0
- package/src/roots/published-reach.ts +486 -0
- package/src/{roots.ts → roots/root-set.ts} +286 -469
- package/src/roots/unseen-loads.ts +345 -0
- package/src/run.ts +75 -91
- package/src/schema.ts +391 -388
- package/src/scope.ts +46 -138
- package/src/serialization-contract.ts +769 -23
- package/src/session.ts +87 -55
- package/src/source-files.ts +6 -11
- package/src/stores.ts +15 -3
- package/src/suppress-file.ts +24 -33
- package/src/suppress-inline.ts +55 -91
- package/src/suppress.ts +78 -79
- package/src/symbol-keys.ts +104 -107
- package/src/template-field.ts +15 -25
- package/src/tests/file-class.ts +135 -0
- package/src/{outside-tests.ts → tests/outside.ts} +16 -10
- package/src/{test-support.ts → tests/support.ts} +15 -21
- package/src/text/compare.ts +27 -0
- package/src/text/glob.ts +210 -0
- package/src/text/named-files.ts +388 -0
- package/src/text/yaml.ts +747 -0
- package/src/type-errors.ts +18 -288
- package/src/type-parameter-reads.ts +187 -158
- package/src/unimplemented-callees.ts +297 -280
- package/src/unwrap.ts +34 -0
- package/src/usage.ts +10 -0
- package/src/vendor/unbash/LICENSE +15 -0
- package/src/vendor/unbash/VENDORED.md +16 -0
- package/src/vendor/unbash/ansi-c.ts +132 -0
- package/src/vendor/unbash/arithmetic-parts.ts +53 -0
- package/src/vendor/unbash/arithmetic.ts +641 -0
- package/src/vendor/unbash/assignment.ts +163 -0
- package/src/vendor/unbash/chars.ts +48 -0
- package/src/vendor/unbash/command.ts +47 -0
- package/src/vendor/unbash/expansion.ts +144 -0
- package/src/vendor/unbash/glob.ts +284 -0
- package/src/vendor/unbash/heredoc.ts +34 -0
- package/src/vendor/unbash/internal-types.ts +94 -0
- package/src/vendor/unbash/lexer.ts +4352 -0
- package/src/vendor/unbash/limits.ts +3 -0
- package/src/vendor/unbash/parser.ts +1612 -0
- package/src/vendor/unbash/parts.ts +96 -0
- package/src/vendor/unbash/substitution-context.ts +20 -0
- package/src/vendor/unbash/traversal.ts +182 -0
- package/src/vendor/unbash/types.ts +660 -0
- package/src/vendor/unbash/word-value.ts +64 -0
- package/src/vendor/unbash/word.ts +50 -0
- package/src/verbs/analyze.ts +255 -164
- package/src/verbs/describe.ts +19 -17
- package/src/verbs/explain.ts +93 -169
- package/src/verbs/print-config.ts +2 -1
- package/src/verbs/print-projects.ts +6 -4
- package/src/verbs/print-retained.ts +7 -5
- package/src/verbs/print-roots.ts +4 -2
- package/src/verbs/verb.ts +2 -8
- package/src/verbs/version.ts +15 -3
- package/dist/src/base-url.js +0 -18
- package/dist/src/conventions.js +0 -937
- package/dist/src/discover.js +0 -468
- package/dist/src/entry-points.js +0 -529
- package/dist/src/glob.js +0 -65
- package/dist/src/manifest.js +0 -165
- package/dist/src/matrix.js +0 -246
- package/dist/src/pnpm-workspace.js +0 -120
- package/dist/src/roots.js +0 -672
- package/dist/src/setup-failure.js +0 -23
- package/dist/src/sweep.js +0 -224
- package/dist/src/test-joins.js +0 -101
- package/dist/src/version.js +0 -7
- package/dist/src/workflow-steps.js +0 -185
- package/src/base-url.ts +0 -24
- package/src/discover.ts +0 -653
- package/src/entry-points.ts +0 -687
- package/src/glob.ts +0 -67
- package/src/manifest.ts +0 -234
- package/src/matrix.ts +0 -423
- package/src/pnpm-workspace.ts +0 -135
- package/src/setup-failure.ts +0 -39
- package/src/sweep.ts +0 -347
- package/src/test-joins.ts +0 -120
- package/src/version.ts +0 -7
- package/src/workflow-steps.ts +0 -216
|
@@ -1,21 +1,26 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.ts";
|
|
1
2
|
import type { Finding, FindingDetails, FindingPosition } from "../finding.ts";
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
3
|
+
import { WORDS, type InventorySymbol } from "../inventory.ts";
|
|
4
|
+
import type { Candidate } from "../liveness/sweep.ts";
|
|
4
5
|
import { positionKey } from "../position.ts";
|
|
5
6
|
import { declarationKey } from "../ref.ts";
|
|
7
|
+
import { reachabilityClasses } from "./completion.ts";
|
|
6
8
|
import type { Emitter, EmitterInput } from "./emitter.ts";
|
|
7
9
|
|
|
8
|
-
|
|
9
|
-
type ReadsAndWritesCode = "DS1301" | "DS1302" | "DS1303";
|
|
10
|
+
import { bytewise } from "../text/compare.ts";
|
|
10
11
|
|
|
11
|
-
/** The
|
|
12
|
-
|
|
12
|
+
/** The codes this emitter reports. */
|
|
13
|
+
type ReadsAndWritesCode =
|
|
14
|
+
typeof CODE.writeOnlySymbol | typeof CODE.unusedEnumMember | typeof CODE.unusedTypeParameter;
|
|
13
15
|
|
|
14
|
-
/**
|
|
16
|
+
/** The containers whose type parameters `DS1006` reports: a function, a class method and a type alias. */
|
|
17
|
+
const SIGNATURES: ReadonlySet<string> = new Set(["function", "method", "type"]);
|
|
18
|
+
|
|
19
|
+
/** What this emitter reads of one run, indexed by declaration. */
|
|
15
20
|
interface Run {
|
|
16
21
|
readonly input: EmitterInput;
|
|
17
22
|
readonly symbols: ReadonlyMap<string, InventorySymbol>;
|
|
18
|
-
readonly candidates: ReadonlyMap<string,
|
|
23
|
+
readonly candidates: ReadonlyMap<string, Candidate>;
|
|
19
24
|
}
|
|
20
25
|
|
|
21
26
|
function indexed(input: EmitterInput): Run {
|
|
@@ -109,19 +114,16 @@ function parametersOnlyNamedBy(
|
|
|
109
114
|
}
|
|
110
115
|
|
|
111
116
|
/** What one write-only finding says, the declarations its deletion takes with it included. */
|
|
112
|
-
function writeOnlyMessage(
|
|
113
|
-
|
|
114
|
-
namedBy: ReadonlyMap<string, ReadonlySet<string>>,
|
|
115
|
-
symbol: InventorySymbol,
|
|
116
|
-
held: Uses,
|
|
117
|
-
): string {
|
|
117
|
+
function writeOnlyMessage(run: Run, written: Written, subject: Subject): string {
|
|
118
|
+
const { symbol, held } = subject;
|
|
118
119
|
const writes = held.writes.length === 1 ? "once" : `at ${String(held.writes.length)} positions`;
|
|
119
120
|
const read = run.input.stores.readInTests.has(symbol.id)
|
|
120
121
|
? "read only from test files"
|
|
121
122
|
: "never read";
|
|
122
123
|
const cascade = [
|
|
123
|
-
...parametersOnlyNamedBy(run, namedBy, symbol).map((name) => `type parameter ${name}`),
|
|
124
|
-
...[...held.alone].sort().map((name) => `import ${name}`),
|
|
124
|
+
...parametersOnlyNamedBy(run, written.namedBy, symbol).map((name) => `type parameter ${name}`),
|
|
125
|
+
...[...held.alone].sort(bytewise).map((name) => `import ${name}`),
|
|
126
|
+
...(written.named.get(symbol.id) ?? []),
|
|
125
127
|
];
|
|
126
128
|
const word = SUBJECT_WORDS[symbol.kind] ?? "member";
|
|
127
129
|
const message = `${word} ${symbol.name} is written ${writes} and ${read}`;
|
|
@@ -130,17 +132,55 @@ function writeOnlyMessage(
|
|
|
130
132
|
: `${message}, and deleting it with its writes deletes ${cascade.join(" and ")} too`;
|
|
131
133
|
}
|
|
132
134
|
|
|
135
|
+
/** One declaration the write-only kind reports, with its uses. */
|
|
136
|
+
interface Subject {
|
|
137
|
+
readonly symbol: InventorySymbol;
|
|
138
|
+
readonly held: Uses;
|
|
139
|
+
}
|
|
140
|
+
|
|
133
141
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
142
|
+
* What the write-only kind answers of one run: its subjects in site order, and the
|
|
143
|
+
* declarations that fall with them, each named under the innermost subject of every chain
|
|
144
|
+
* of carriers its references hold.
|
|
145
|
+
*/
|
|
146
|
+
interface Written {
|
|
147
|
+
readonly subjects: readonly Subject[];
|
|
148
|
+
readonly namedBy: ReadonlyMap<string, ReadonlySet<string>>;
|
|
149
|
+
readonly named: ReadonlyMap<string, readonly string[]>;
|
|
150
|
+
readonly falls: ReadonlySet<string>;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* The kinds of declaration that fall with a write-only subject: a declaration of its own.
|
|
155
|
+
* A member falls with its container, and a type parameter is the type-parameter clause's.
|
|
156
|
+
*/
|
|
157
|
+
const FALLING: ReadonlySet<InventorySymbol["kind"]> = new Set([
|
|
158
|
+
"function",
|
|
159
|
+
"class",
|
|
160
|
+
"interface",
|
|
161
|
+
"type",
|
|
162
|
+
"enum",
|
|
163
|
+
"namespace",
|
|
164
|
+
"variable",
|
|
165
|
+
]);
|
|
166
|
+
|
|
167
|
+
const WRITTEN = new WeakMap<EmitterInput, Written>();
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* `DS1301`'s subjects: a module-level variable, a type member or a class member the
|
|
171
|
+
* counted references store into and never read.
|
|
136
172
|
*
|
|
137
173
|
* The subject is a live declaration: a store is a reference, so the sweep holds a
|
|
138
174
|
* written one live and its candidates are never this kind's. Every reference that is
|
|
139
175
|
* not a store reads, and so does an exemption record naming the declaration.
|
|
140
176
|
*/
|
|
141
|
-
function
|
|
177
|
+
function writtenOf(run: Run): Written {
|
|
178
|
+
const known = WRITTEN.get(run.input);
|
|
179
|
+
if (known !== undefined) {
|
|
180
|
+
return known;
|
|
181
|
+
}
|
|
142
182
|
const { stores } = run.input;
|
|
143
|
-
const { matrix } = run.input.swept;
|
|
183
|
+
const { matrix, sweep } = run.input.swept;
|
|
144
184
|
const uses = new Map<string, Uses>();
|
|
145
185
|
for (const reference of stores.references) {
|
|
146
186
|
let held = uses.get(reference.to);
|
|
@@ -171,26 +211,54 @@ function writeOnlySymbols(run: Run): readonly Finding[] {
|
|
|
171
211
|
}
|
|
172
212
|
}
|
|
173
213
|
|
|
174
|
-
const
|
|
175
|
-
for (const symbol of matrix.union.symbols) {
|
|
214
|
+
const subjects = matrix.union.symbols.flatMap((symbol): Subject[] => {
|
|
176
215
|
const held = uses.get(symbol.id);
|
|
177
|
-
|
|
178
|
-
held === undefined ||
|
|
216
|
+
return held === undefined ||
|
|
179
217
|
held.writes.length === 0 ||
|
|
180
218
|
held.reads > 0 ||
|
|
181
219
|
!writable(run, symbol) ||
|
|
182
220
|
stores.exempt.has(symbol.id) ||
|
|
183
221
|
run.candidates.has(symbol.id)
|
|
222
|
+
? []
|
|
223
|
+
: [{ symbol, held }];
|
|
224
|
+
});
|
|
225
|
+
const subjectIds = new Set(subjects.map((subject) => subject.symbol.id));
|
|
226
|
+
const classOf = reachabilityClasses(run.input);
|
|
227
|
+
const named = new Map<string, string[]>();
|
|
228
|
+
const falls = new Set<string>();
|
|
229
|
+
for (const symbol of matrix.union.symbols) {
|
|
230
|
+
const chains = sweep.carried.get(symbol.id);
|
|
231
|
+
if (
|
|
232
|
+
chains === undefined ||
|
|
233
|
+
subjectIds.has(symbol.id) ||
|
|
234
|
+
!FALLING.has(symbol.kind) ||
|
|
235
|
+
classOf(symbol.id) !== "certain"
|
|
184
236
|
) {
|
|
185
237
|
continue;
|
|
186
238
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
);
|
|
239
|
+
const innermost = chains.map((chain) => chain.find((id) => subjectIds.has(id)));
|
|
240
|
+
if (innermost.includes(undefined)) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
falls.add(symbol.id);
|
|
244
|
+
for (const subject of new Set(innermost)) {
|
|
245
|
+
const name = `${WORDS[symbol.kind]} ${symbol.name}`;
|
|
246
|
+
named.set(subject ?? "", [...(named.get(subject ?? "") ?? []), name]);
|
|
247
|
+
}
|
|
192
248
|
}
|
|
193
|
-
|
|
249
|
+
const written = { subjects, namedBy, named, falls };
|
|
250
|
+
WRITTEN.set(run.input, written);
|
|
251
|
+
return written;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** `DS1301`: each subject, named with every position written and what falls with it. */
|
|
255
|
+
function writeOnlySymbols(run: Run): readonly Finding[] {
|
|
256
|
+
const written = writtenOf(run);
|
|
257
|
+
return written.subjects.map((subject) =>
|
|
258
|
+
findingAbout(subject.symbol, CODE.writeOnlySymbol, writeOnlyMessage(run, written, subject), {
|
|
259
|
+
writePositions: subject.held.writes,
|
|
260
|
+
}),
|
|
261
|
+
);
|
|
194
262
|
}
|
|
195
263
|
|
|
196
264
|
/**
|
|
@@ -214,21 +282,22 @@ function unnamed(run: Run, kind: InventorySymbol["kind"]): readonly InventorySym
|
|
|
214
282
|
}
|
|
215
283
|
|
|
216
284
|
/**
|
|
217
|
-
* `
|
|
285
|
+
* `DS1005`: a member of an enum declaration that nothing names. A member an enum-group
|
|
218
286
|
* record holds back is no candidate, so a member a conversion can produce never reaches
|
|
219
287
|
* this kind.
|
|
220
288
|
*/
|
|
221
289
|
function unusedEnumMembers(run: Run): readonly Finding[] {
|
|
222
290
|
return unnamed(run, "enum-member").map((symbol) =>
|
|
223
|
-
findingAbout(symbol,
|
|
291
|
+
findingAbout(symbol, CODE.unusedEnumMember, `enum member ${symbol.name} is named nowhere`),
|
|
224
292
|
);
|
|
225
293
|
}
|
|
226
294
|
|
|
227
295
|
/**
|
|
228
|
-
* `
|
|
229
|
-
* declaration's signature nor its body names.
|
|
230
|
-
* a
|
|
231
|
-
*
|
|
296
|
+
* `DS1006`: a type parameter of a function, a class method or a type alias that neither
|
|
297
|
+
* the declaration's signature nor its body names. An alias names no type of its own, so
|
|
298
|
+
* a parameter its type never names makes no two instantiations distinct. One of a class,
|
|
299
|
+
* an interface or a method signature is never reported: a class or an interface merges
|
|
300
|
+
* only with declarations of the same parameters.
|
|
232
301
|
*/
|
|
233
302
|
function unusedTypeParameters(run: Run): readonly Finding[] {
|
|
234
303
|
return unnamed(run, "type-parameter")
|
|
@@ -236,7 +305,7 @@ function unusedTypeParameters(run: Run): readonly Finding[] {
|
|
|
236
305
|
.map((symbol) =>
|
|
237
306
|
findingAbout(
|
|
238
307
|
symbol,
|
|
239
|
-
|
|
308
|
+
CODE.unusedTypeParameter,
|
|
240
309
|
`type parameter ${symbol.name} is named in neither its signature nor its body`,
|
|
241
310
|
),
|
|
242
311
|
);
|
|
@@ -249,15 +318,23 @@ function unusedTypeParameters(run: Run): readonly Finding[] {
|
|
|
249
318
|
*/
|
|
250
319
|
export function writeOnlyDeclarations(input: EmitterInput): ReadonlySet<string> {
|
|
251
320
|
return new Set(
|
|
252
|
-
|
|
253
|
-
declarationKey(
|
|
321
|
+
writtenOf(indexed(input)).subjects.map(({ symbol }) =>
|
|
322
|
+
declarationKey(symbol.ref, symbol.position.path),
|
|
254
323
|
),
|
|
255
324
|
);
|
|
256
325
|
}
|
|
257
326
|
|
|
258
327
|
/**
|
|
259
|
-
* The
|
|
260
|
-
*
|
|
328
|
+
* The declarations that fall with a write-only subject, whatever the severity: a finding
|
|
329
|
+
* about one would name code its subject's deletion already deletes.
|
|
330
|
+
*/
|
|
331
|
+
export function fallingWithWrites(input: EmitterInput): ReadonlySet<string> {
|
|
332
|
+
return writtenOf(indexed(input)).falls;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* The findings of the reads-and-writes kinds, `DS1301`, `DS1005` and `DS1006`, in that
|
|
337
|
+
* order and each code's in site order.
|
|
261
338
|
*/
|
|
262
339
|
export const readsAndWrites: Emitter = (input) => {
|
|
263
340
|
const run = indexed(input);
|
|
@@ -1,24 +1,18 @@
|
|
|
1
|
+
import { CODE, REMEDIES, type Subject } 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";
|
|
4
5
|
import { FIXED_SEVERITY_CODES } from "../kinds.ts";
|
|
5
6
|
import type { Position } from "../position.ts";
|
|
6
7
|
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
STALE_SUPPRESSION,
|
|
10
|
-
SUPPRESSION_WITHOUT_REASON,
|
|
8
|
+
names,
|
|
9
|
+
subjectOfCode,
|
|
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
|
-
|
|
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";
|
|
15
|
+
import { bytewise } from "../text/compare.ts";
|
|
22
16
|
|
|
23
17
|
/** The subject kind of a finding about a configured declaration. */
|
|
24
18
|
const DECLARATION_SUBJECT = "configured-declaration";
|
|
@@ -39,7 +33,7 @@ export interface StaleRecord {
|
|
|
39
33
|
readonly reports: readonly string[];
|
|
40
34
|
}
|
|
41
35
|
|
|
42
|
-
/** What the
|
|
36
|
+
/** What the configuration family reads: the run's refused suppressions and its configured roots. */
|
|
43
37
|
export interface SelfCheckFacts {
|
|
44
38
|
/** The suppressions the grammar refused with a finding, in reading order. */
|
|
45
39
|
readonly refusals: readonly Refusal[];
|
|
@@ -78,6 +72,43 @@ export function fileRefsOf(symbols: readonly InventorySymbol[]): FileRefs {
|
|
|
78
72
|
return (path) => byPath.get(path);
|
|
79
73
|
}
|
|
80
74
|
|
|
75
|
+
/**
|
|
76
|
+
* Why a record of `mechanism` naming `codes` can match nothing, one clause per subject whose
|
|
77
|
+
* findings kinds.json's remedies table lets no record of that mechanism name, in subject order.
|
|
78
|
+
*/
|
|
79
|
+
function unnameable(codes: readonly string[], mechanism: Mechanism): readonly string[] {
|
|
80
|
+
return (Object.keys(REMEDIES) as Subject[]).flatMap((subject) => {
|
|
81
|
+
const named = codes.filter((code) => subjectOfCode(code) === subject);
|
|
82
|
+
if (named.length === 0 || names(subject, mechanism)) {
|
|
83
|
+
return [];
|
|
84
|
+
}
|
|
85
|
+
const { names: what, suppressions } = REMEDIES[subject];
|
|
86
|
+
const reports = `${spelled(named)} ${named.length === 1 ? "reports" : "each report"} ${what}`;
|
|
87
|
+
if (suppressions.length > 0) {
|
|
88
|
+
const records = suppressions.map((one) => articled(WRITTEN[one]));
|
|
89
|
+
return [`${reports}, which only ${spelledOr(records)} can name`];
|
|
90
|
+
}
|
|
91
|
+
const settable = named.filter((code) => !FIXED_SEVERITY_CODES.includes(code));
|
|
92
|
+
const remedy =
|
|
93
|
+
settable.length === 0
|
|
94
|
+
? "fix what the finding names instead"
|
|
95
|
+
: `fix what the finding names or set the severity of ${spelled(settable)} instead`;
|
|
96
|
+
return [`${reports}, which no suppression can name; ${remedy}`];
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** A record's written name with its indefinite article. */
|
|
101
|
+
function articled(name: string): string {
|
|
102
|
+
return `${/^[aeiou]/u.test(name) ? "an" : "a"} ${name}`;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** A list as a sentence names alternatives. */
|
|
106
|
+
function spelledOr(items: readonly string[]): string {
|
|
107
|
+
return items.length < 2
|
|
108
|
+
? items.join("")
|
|
109
|
+
: `${items.slice(0, -1).join(", ")} or ${items.at(-1) ?? ""}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
81
112
|
/** A list of codes as a sentence names them. */
|
|
82
113
|
function spelled(codes: readonly string[]): string {
|
|
83
114
|
if (codes.length < 2) {
|
|
@@ -135,7 +166,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
|
|
|
135
166
|
suppressionRef(refused.symbol, refused.path, files),
|
|
136
167
|
refused.site,
|
|
137
168
|
`${WRITTEN[refused.mechanism]} for ${refused.code} ${
|
|
138
|
-
refused.reported ===
|
|
169
|
+
refused.reported === CODE.suppressionWithoutReason
|
|
139
170
|
? "carries no reason"
|
|
140
171
|
: "names a symbol and no path"
|
|
141
172
|
}`,
|
|
@@ -146,7 +177,7 @@ function refusedSuppressions(refusals: readonly Refusal[], files: FileRefs): rea
|
|
|
146
177
|
|
|
147
178
|
/** One stale suppression as the report's stale-suppression record carries it. */
|
|
148
179
|
export interface StaleSuppression {
|
|
149
|
-
readonly code: typeof
|
|
180
|
+
readonly code: typeof CODE.staleSuppression;
|
|
150
181
|
readonly mechanism: Mechanism;
|
|
151
182
|
readonly entry: {
|
|
152
183
|
readonly code: string;
|
|
@@ -178,30 +209,12 @@ export function staleSuppressions(
|
|
|
178
209
|
bySite.set(key, held);
|
|
179
210
|
}
|
|
180
211
|
return [...bySite.values()].map(({ first, records }) => {
|
|
181
|
-
const codes = [...new Set(records.map((one) => one.record.code))].sort();
|
|
212
|
+
const codes = [...new Set(records.map((one) => one.record.code))].sort(bytewise);
|
|
182
213
|
const reports = [...new Set(records.flatMap((one) => one.reports))]
|
|
183
214
|
.filter((code) => !codes.includes(code))
|
|
184
|
-
.sort();
|
|
185
|
-
const rows = codes.filter(isUnsuppressibleCode);
|
|
186
|
-
const dependencies = first.mechanism === "inline" ? codes.filter(isDependencyCode) : [];
|
|
187
|
-
const settable = rows.filter((code) => !FIXED_SEVERITY_CODES.includes(code));
|
|
188
|
-
const remedy =
|
|
189
|
-
settable.length === 0
|
|
190
|
-
? "fix what the finding names instead"
|
|
191
|
-
: `fix what the finding names or set the severity of ${spelled(settable)} instead`;
|
|
215
|
+
.sort(bytewise);
|
|
192
216
|
const declared = reports.length === 0 ? "" : `its declaration reports ${spelled(reports)}`;
|
|
193
|
-
const because =
|
|
194
|
-
...(rows.length > 0
|
|
195
|
-
? [
|
|
196
|
-
`${spelled(rows)} ${rows.length === 1 ? "reports a row" : "report rows"} of a document, which no suppression can name; ${remedy}`,
|
|
197
|
-
]
|
|
198
|
-
: []),
|
|
199
|
-
...(dependencies.length > 0
|
|
200
|
-
? [
|
|
201
|
-
`${spelled(dependencies)} ${dependencies.length === 1 ? "reports a dependency row" : "report dependency rows"}, which only an ignore entry or a baseline row can name`,
|
|
202
|
-
]
|
|
203
|
-
: []),
|
|
204
|
-
];
|
|
217
|
+
const because = unnameable(codes, first.mechanism);
|
|
205
218
|
const instead =
|
|
206
219
|
because.length > 0
|
|
207
220
|
? `, because ${because.join("; ")}${declared === "" ? "" : `; ${declared}`}`
|
|
@@ -209,7 +222,7 @@ export function staleSuppressions(
|
|
|
209
222
|
? ""
|
|
210
223
|
: `, and ${declared}`;
|
|
211
224
|
return {
|
|
212
|
-
code:
|
|
225
|
+
code: CODE.staleSuppression,
|
|
213
226
|
mechanism: first.mechanism,
|
|
214
227
|
entry: {
|
|
215
228
|
code: first.code,
|
|
@@ -242,7 +255,7 @@ function unmatchedDeclarationFindings(
|
|
|
242
255
|
unmatched: readonly UnmatchedDeclaration[],
|
|
243
256
|
): readonly Finding[] {
|
|
244
257
|
return unmatched.map((one) => ({
|
|
245
|
-
code:
|
|
258
|
+
code: CODE.unmatchedConfiguredDeclaration,
|
|
246
259
|
position: documentPosition(one.document),
|
|
247
260
|
symbol: { ref: one.ref, kind: DECLARATION_SUBJECT, name: one.ref, sizeLines: 1 },
|
|
248
261
|
message: `${one.key} entry names no declaration in any project`,
|
|
@@ -262,7 +275,7 @@ export function unmatchedRootFindings(
|
|
|
262
275
|
): readonly Finding[] {
|
|
263
276
|
const position = documentPosition(document);
|
|
264
277
|
return sources.map((source) => ({
|
|
265
|
-
code:
|
|
278
|
+
code: CODE.unmatchedRoot,
|
|
266
279
|
position,
|
|
267
280
|
symbol: { ref: source, kind: ROOT_SUBJECT, name: source, sizeLines: 1 },
|
|
268
281
|
message:
|
|
@@ -273,7 +286,7 @@ export function unmatchedRootFindings(
|
|
|
273
286
|
}
|
|
274
287
|
|
|
275
288
|
/**
|
|
276
|
-
* The findings of the
|
|
289
|
+
* The findings of the configuration family, `DS9000` to `DS9099`: a suppression refused for
|
|
277
290
|
* carrying no reason or naming no path, and a configured root or declaration that named
|
|
278
291
|
* nothing. A
|
|
279
292
|
* suppression that matched nothing is a record of the report's stale suppressions, which
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { CODE } from "../contract/contract.generated.ts";
|
|
1
2
|
import type { Finding } from "../finding.ts";
|
|
2
|
-
import type
|
|
3
|
-
import type {
|
|
3
|
+
import { WORDS, type InventorySymbol, type SymbolKind } from "../inventory.ts";
|
|
4
|
+
import type { Candidate } from "../liveness/sweep.ts";
|
|
4
5
|
import type { Emitter, EmitterInput } from "./emitter.ts";
|
|
5
6
|
import { unreachableExports } from "./visibility-narrowing.ts";
|
|
6
7
|
|
|
@@ -13,42 +14,23 @@ const MEMBERS: ReadonlySet<SymbolKind> = new Set([
|
|
|
13
14
|
]);
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
|
-
* The kinds of declaration no code of this
|
|
17
|
+
* The kinds of declaration no code of this emitter reports: an interface and a method an
|
|
17
18
|
* interface declares are the interface kinds' subjects, and a type parameter is the
|
|
18
19
|
* subject of the unused-type-parameter kind or of none.
|
|
19
20
|
*/
|
|
20
|
-
const
|
|
21
|
+
const NOT_REPORTED_HERE: ReadonlySet<SymbolKind> = new Set([
|
|
21
22
|
"file",
|
|
22
23
|
"interface",
|
|
23
24
|
"interface-method",
|
|
24
25
|
"type-parameter",
|
|
25
26
|
]);
|
|
26
27
|
|
|
27
|
-
/** The reader's word for each kind of declaration a finding of the family names. */
|
|
28
|
-
const WORDS: Readonly<Record<SymbolKind, string>> = {
|
|
29
|
-
file: "file",
|
|
30
|
-
function: "function",
|
|
31
|
-
class: "class",
|
|
32
|
-
interface: "interface",
|
|
33
|
-
type: "type alias",
|
|
34
|
-
enum: "enum",
|
|
35
|
-
namespace: "namespace",
|
|
36
|
-
variable: "variable",
|
|
37
|
-
"export-alias": "re-export",
|
|
38
|
-
method: "method",
|
|
39
|
-
"class-member": "class member",
|
|
40
|
-
"interface-method": "interface method",
|
|
41
|
-
"type-member": "type member",
|
|
42
|
-
"enum-member": "enum member",
|
|
43
|
-
"type-parameter": "type parameter",
|
|
44
|
-
};
|
|
45
|
-
|
|
46
28
|
/** What the test-of-dead-code kind says, which states the rule it applies. */
|
|
47
29
|
const TEST_OF_DEAD_CODE = "every target symbol this test references is reported dead";
|
|
48
30
|
|
|
49
31
|
/** What the run holds about one candidate that decides its code. */
|
|
50
32
|
interface Judged {
|
|
51
|
-
readonly candidate:
|
|
33
|
+
readonly candidate: Candidate;
|
|
52
34
|
readonly symbol: InventorySymbol;
|
|
53
35
|
/** Whether a test file declares it. */
|
|
54
36
|
readonly test: boolean;
|
|
@@ -68,9 +50,9 @@ interface Judged {
|
|
|
68
50
|
function codeOf(judged: Judged): string | undefined {
|
|
69
51
|
const { candidate, symbol } = judged;
|
|
70
52
|
if (candidate.testOfDeadCode) {
|
|
71
|
-
return
|
|
53
|
+
return CODE.testOfDeadCode;
|
|
72
54
|
}
|
|
73
|
-
if ((judged.test && !candidate.unreferencedTest) ||
|
|
55
|
+
if ((judged.test && !candidate.unreferencedTest) || NOT_REPORTED_HERE.has(symbol.kind)) {
|
|
74
56
|
return undefined;
|
|
75
57
|
}
|
|
76
58
|
const referenced = candidate.productionRefs + candidate.testRefs > 0;
|
|
@@ -81,33 +63,33 @@ function codeOf(judged: Judged): string | undefined {
|
|
|
81
63
|
return unreferencedCode(symbol);
|
|
82
64
|
}
|
|
83
65
|
if (candidate.heldByTests === candidate.id) {
|
|
84
|
-
return
|
|
66
|
+
return CODE.testOnlyUse;
|
|
85
67
|
}
|
|
86
68
|
if (candidate.productionRefs === 0 && judged.deprecated) {
|
|
87
|
-
return
|
|
69
|
+
return CODE.deprecatedUnused;
|
|
88
70
|
}
|
|
89
71
|
if (
|
|
90
72
|
candidate.testRefs > 0 &&
|
|
91
73
|
(candidate.productionRefs === 0 ||
|
|
92
74
|
(candidate.relation === "reachability" && candidate.keptByTests))
|
|
93
75
|
) {
|
|
94
|
-
return
|
|
76
|
+
return CODE.testOnlyUse;
|
|
95
77
|
}
|
|
96
78
|
if (MEMBERS.has(symbol.kind)) {
|
|
97
|
-
return
|
|
79
|
+
return CODE.unusedMember;
|
|
98
80
|
}
|
|
99
81
|
if (!symbol.exported) {
|
|
100
|
-
return
|
|
82
|
+
return CODE.unusedUnexported;
|
|
101
83
|
}
|
|
102
|
-
return judged.unreachable ? undefined :
|
|
84
|
+
return judged.unreachable ? undefined : CODE.unusedExported;
|
|
103
85
|
}
|
|
104
86
|
|
|
105
87
|
/** The code a declaration nothing references carries, by its shape and its visibility. */
|
|
106
88
|
function unreferencedCode(symbol: InventorySymbol): string {
|
|
107
89
|
if (MEMBERS.has(symbol.kind)) {
|
|
108
|
-
return
|
|
90
|
+
return CODE.unusedMember;
|
|
109
91
|
}
|
|
110
|
-
return symbol.exported ?
|
|
92
|
+
return symbol.exported ? CODE.unusedExported : CODE.unusedUnexported;
|
|
111
93
|
}
|
|
112
94
|
|
|
113
95
|
/** The visibility a member's message names, where it narrows the member's reach. */
|
|
@@ -132,17 +114,17 @@ function messageOf(code: string, judged: Judged): string {
|
|
|
132
114
|
const { candidate, symbol } = judged;
|
|
133
115
|
const word = WORDS[symbol.kind];
|
|
134
116
|
switch (code) {
|
|
135
|
-
case
|
|
117
|
+
case CODE.testOfDeadCode:
|
|
136
118
|
return TEST_OF_DEAD_CODE;
|
|
137
|
-
case
|
|
119
|
+
case CODE.deprecatedUnused:
|
|
138
120
|
return `deprecated ${word} has no production reference`;
|
|
139
|
-
case
|
|
121
|
+
case CODE.testOnlyUse:
|
|
140
122
|
return candidate.productionRefs === 0
|
|
141
123
|
? `${word} is referenced only from test files and never from production code`
|
|
142
124
|
: `${word} is referenced only from test files and from declarations that are themselves dead`;
|
|
143
125
|
}
|
|
144
126
|
const subject =
|
|
145
|
-
code ===
|
|
127
|
+
code === CODE.unusedMember
|
|
146
128
|
? `${visibilityWord(symbol)}${word}`
|
|
147
129
|
: symbol.kind === "export-alias"
|
|
148
130
|
? word
|
|
@@ -150,7 +132,7 @@ function messageOf(code: string, judged: Judged): string {
|
|
|
150
132
|
if (candidate.relation === "reachability") {
|
|
151
133
|
return `${subject} is referenced only from declarations that are themselves dead`;
|
|
152
134
|
}
|
|
153
|
-
if (code ===
|
|
135
|
+
if (code === CODE.unusedExported) {
|
|
154
136
|
return `${subject} has no reference in the target and none from any loaded consumer`;
|
|
155
137
|
}
|
|
156
138
|
return `${subject} has no reference in the target`;
|
|
@@ -202,25 +184,25 @@ function brandMembers(input: EmitterInput): ReadonlySet<string> {
|
|
|
202
184
|
/** The kinds of member a brand is: a data member of a type or of a class. */
|
|
203
185
|
const BRANDS: ReadonlySet<SymbolKind> = new Set(["type-member", "class-member"]);
|
|
204
186
|
|
|
205
|
-
/** The findings of the unused-
|
|
187
|
+
/** The findings of the unused-declaration kinds, `DS1001` to `DS1004` and `DS1102` to `DS1104`. */
|
|
206
188
|
export const unusedDeclarations: Emitter = (input) => [
|
|
207
|
-
...
|
|
189
|
+
...emitterFindings(input, false),
|
|
208
190
|
...unusedImports(input),
|
|
209
191
|
];
|
|
210
192
|
|
|
211
193
|
/**
|
|
212
|
-
* The import bindings their file never reads
|
|
213
|
-
*
|
|
194
|
+
* The import bindings their file never reads. A generated file's are the generator's to
|
|
195
|
+
* remove unless the run includes generated files.
|
|
214
196
|
*/
|
|
215
197
|
function unusedImports(input: EmitterInput): Finding[] {
|
|
216
198
|
const generated =
|
|
217
|
-
input.config.analysis.
|
|
199
|
+
input.config.analysis.generated_files === "include" ? undefined : input.files.generated;
|
|
218
200
|
return input.intraFunction.imports.flatMap((binding) =>
|
|
219
201
|
binding.used || generated?.has(binding.position.path) === true
|
|
220
202
|
? []
|
|
221
203
|
: [
|
|
222
204
|
{
|
|
223
|
-
code:
|
|
205
|
+
code: CODE.unusedImport,
|
|
224
206
|
position: binding.position,
|
|
225
207
|
symbol: { ref: binding.ref, kind: "import", name: binding.name, sizeLines: 1 },
|
|
226
208
|
message: `import binding ${binding.name} is never read in its file`,
|
|
@@ -234,10 +216,10 @@ function unusedImports(input: EmitterInput): Finding[] {
|
|
|
234
216
|
* a record on such a member is matched against, since the report carries the container's
|
|
235
217
|
* finding rather than one of the member's own.
|
|
236
218
|
*/
|
|
237
|
-
export const fallenMembers: Emitter = (input) =>
|
|
219
|
+
export const fallenMembers: Emitter = (input) => emitterFindings(input, true);
|
|
238
220
|
|
|
239
|
-
/**
|
|
240
|
-
function
|
|
221
|
+
/** This emitter's findings, or, where `fallen` is set, its dead containers' members' alone. */
|
|
222
|
+
function emitterFindings(input: EmitterInput, fallen: boolean): Finding[] {
|
|
241
223
|
const union = input.swept.matrix.union;
|
|
242
224
|
const dead = new Set(input.swept.sweep.candidates.map((candidate) => candidate.id));
|
|
243
225
|
const unreachable = unreachableExports(input);
|
|
@@ -264,7 +246,7 @@ function familyFindings(input: EmitterInput, fallen: boolean): Finding[] {
|
|
|
264
246
|
const code = codeOf(judged);
|
|
265
247
|
if (
|
|
266
248
|
code === undefined ||
|
|
267
|
-
(code ===
|
|
249
|
+
(code === CODE.unusedMember && (brands ??= brandMembers(input)).has(symbol.id))
|
|
268
250
|
) {
|
|
269
251
|
continue;
|
|
270
252
|
}
|