@iris-code/core 0.1.2 → 0.2.0
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/config.d.ts +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -1
- package/dist/config.js.map +1 -1
- package/dist/fileNaming.d.ts +1 -0
- package/dist/fileNaming.d.ts.map +1 -1
- package/dist/fileNaming.js +29 -0
- package/dist/fileNaming.js.map +1 -1
- package/dist/guards.d.ts.map +1 -1
- package/dist/guards.js +44 -2
- package/dist/guards.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -9
- package/dist/index.js.map +1 -1
- package/dist/java/analyser.d.ts +4 -0
- package/dist/java/analyser.d.ts.map +1 -0
- package/dist/java/analyser.js +394 -0
- package/dist/java/analyser.js.map +1 -0
- package/dist/java/lexer.d.ts +46 -0
- package/dist/java/lexer.d.ts.map +1 -0
- package/dist/java/lexer.js +198 -0
- package/dist/java/lexer.js.map +1 -0
- package/dist/languages.d.ts +2 -10
- package/dist/languages.d.ts.map +1 -1
- package/dist/languages.js +18 -35
- package/dist/languages.js.map +1 -1
- package/dist/registry.d.ts +39 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +74 -0
- package/dist/registry.js.map +1 -0
- package/dist/rust/analyser.d.ts +26 -0
- package/dist/rust/analyser.d.ts.map +1 -0
- package/dist/rust/analyser.js +506 -0
- package/dist/rust/analyser.js.map +1 -0
- package/dist/rust/lexer.d.ts +39 -0
- package/dist/rust/lexer.d.ts.map +1 -0
- package/dist/rust/lexer.js +192 -0
- package/dist/rust/lexer.js.map +1 -0
- package/dist/secrets.d.ts.map +1 -1
- package/dist/secrets.js +357 -1
- package/dist/secrets.js.map +1 -1
- package/dist/sfc.d.ts.map +1 -1
- package/dist/sfc.js +4 -18
- package/dist/sfc.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,506 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.testRanges = testRanges;
|
|
4
|
+
exports.unsafeWithoutSafetyComment = unsafeWithoutSafetyComment;
|
|
5
|
+
exports.analyseRust = analyseRust;
|
|
6
|
+
const lines_1 = require("../lines");
|
|
7
|
+
const scoring_1 = require("../scoring");
|
|
8
|
+
const secrets_1 = require("../secrets");
|
|
9
|
+
const guards_1 = require("../guards");
|
|
10
|
+
const lexer_1 = require("./lexer");
|
|
11
|
+
const ZEROED_TS_METRICS = {
|
|
12
|
+
anyUsages: [], tsIgnoreCount: 0, tsExpectErrorCount: 0,
|
|
13
|
+
nonNullAssertions: 0, typeAssertions: 0, missingReturnTypes: 0,
|
|
14
|
+
};
|
|
15
|
+
function emptyRustSmells() {
|
|
16
|
+
return {
|
|
17
|
+
consoleLogs: [], todos: [], deepNesting: 0, longParameterLists: [],
|
|
18
|
+
magicNumbers: [], unusedVars: [], unusedFunctions: [], bareSuppressions: [],
|
|
19
|
+
duplicateBlocks: [], fileNamingViolations: [], evalUsage: [],
|
|
20
|
+
sqlConcatenation: [], insecureRandom: [], unsafeRegex: [],
|
|
21
|
+
hardcodedLocalhost: [], disabledTlsVerification: [], debugFlagsEnabled: [],
|
|
22
|
+
weakHashing: [], openRedirect: [],
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Lines that legitimately carry a literal number in Rust: a `const` or `static`
|
|
27
|
+
* item, or an attribute argument. Each of those IS the name for its number,
|
|
28
|
+
* which is what the magic-number rule asks for.
|
|
29
|
+
*
|
|
30
|
+
* Matches the exemption C# has had since it shipped, and Java gained in the same
|
|
31
|
+
* change. Found by the benchmark's negative fixture, which reported
|
|
32
|
+
* `const SURCHARGE_MINOR_UNITS: u32 = 4750` as magic.
|
|
33
|
+
*/
|
|
34
|
+
const RUST_MAGIC_NUMBER_EXEMPT_RE = /^\s*#\[|^\s*(?:pub(?:\s*\([^)]*\))?\s+)?(?:const|static)(?:\s+mut)?\s/;
|
|
35
|
+
/** Index of the `}` closing the block whose `{` sits at `openIndex`. */
|
|
36
|
+
function findBlockEnd(code, openIndex) {
|
|
37
|
+
let depth = 0;
|
|
38
|
+
for (let i = openIndex; i < code.length; i++) {
|
|
39
|
+
if (code[i] === '{')
|
|
40
|
+
depth++;
|
|
41
|
+
else if (code[i] === '}') {
|
|
42
|
+
depth--;
|
|
43
|
+
if (depth === 0)
|
|
44
|
+
return i;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
return code.length;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Character ranges covered by `#[cfg(test)]` modules and `#[test]` functions.
|
|
51
|
+
*
|
|
52
|
+
* THIS HAS NO PRECEDENT IN THE OTHER EIGHT LANGUAGES. Every one of them puts
|
|
53
|
+
* tests in separate FILES, so `isTestFile` was enough. Rust puts them inside
|
|
54
|
+
* the file under test:
|
|
55
|
+
*
|
|
56
|
+
* pub fn parse(s: &str) -> u32 { s.parse().unwrap() } // production
|
|
57
|
+
* #[cfg(test)]
|
|
58
|
+
* mod tests { #[test] fn works() { assert_eq!(parse("1"), 1) } }
|
|
59
|
+
*
|
|
60
|
+
* A file-level exemption is either wrong (it exempts the production half too)
|
|
61
|
+
* or useless (it exempts nothing). Without a range-aware exemption, `unwrap()`
|
|
62
|
+
* density floods every well-tested Rust file, which is exactly the population
|
|
63
|
+
* most likely to be evaluating us.
|
|
64
|
+
*/
|
|
65
|
+
function testRanges(source) {
|
|
66
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
67
|
+
const ranges = [];
|
|
68
|
+
const attr = /#\s*\[\s*(?:cfg\s*\(\s*test\s*\)|test|tokio::test|async_std::test)\s*\]/g;
|
|
69
|
+
let match;
|
|
70
|
+
while ((match = attr.exec(code)) !== null) {
|
|
71
|
+
// The attribute applies to the next item, so the range runs from the
|
|
72
|
+
// attribute to the end of that item's block.
|
|
73
|
+
const brace = code.indexOf('{', match.index);
|
|
74
|
+
if (brace === -1)
|
|
75
|
+
continue;
|
|
76
|
+
ranges.push({ start: match.index, end: findBlockEnd(code, brace) });
|
|
77
|
+
}
|
|
78
|
+
return ranges;
|
|
79
|
+
}
|
|
80
|
+
function inTestRange(ranges, index) {
|
|
81
|
+
return ranges.some(range => index >= range.start && index <= range.end);
|
|
82
|
+
}
|
|
83
|
+
const RUST_FN_RE = /(?:^|[{};])\s*(?:#\[[^\]]*\]\s*)*(?:pub(?:\s*\([^)]*\))?\s+)?(?:const\s+|async\s+|unsafe\s+|extern\s+"[^"]*"\s+)*fn\s+([A-Za-z_][\w]*)\s*(?:<[^>]*>)?\s*\(([^)]*)\)/g;
|
|
84
|
+
function countParams(raw) {
|
|
85
|
+
const trimmed = raw.trim();
|
|
86
|
+
if (trimmed === '')
|
|
87
|
+
return 0;
|
|
88
|
+
let depth = 0;
|
|
89
|
+
let count = 1;
|
|
90
|
+
for (const ch of trimmed) {
|
|
91
|
+
if (ch === '<' || ch === '(' || ch === '[')
|
|
92
|
+
depth++;
|
|
93
|
+
else if (ch === '>' || ch === ')' || ch === ']')
|
|
94
|
+
depth--;
|
|
95
|
+
else if (ch === ',' && depth === 0)
|
|
96
|
+
count++;
|
|
97
|
+
}
|
|
98
|
+
return count;
|
|
99
|
+
}
|
|
100
|
+
function detectRustFns(source) {
|
|
101
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
102
|
+
const fns = [];
|
|
103
|
+
RUST_FN_RE.lastIndex = 0;
|
|
104
|
+
let match;
|
|
105
|
+
while ((match = RUST_FN_RE.exec(code)) !== null) {
|
|
106
|
+
const name = match[1];
|
|
107
|
+
const start = match.index + match[0].indexOf(name);
|
|
108
|
+
// A trait method declaration ends in `;` and has no body.
|
|
109
|
+
const brace = code.indexOf('{', match.index + match[0].length);
|
|
110
|
+
const semi = code.indexOf(';', match.index + match[0].length);
|
|
111
|
+
if (brace === -1 || (semi !== -1 && semi < brace))
|
|
112
|
+
continue;
|
|
113
|
+
fns.push({
|
|
114
|
+
name,
|
|
115
|
+
line: (0, lines_1.lineOf)(code, start),
|
|
116
|
+
paramCount: countParams(match[2]),
|
|
117
|
+
start,
|
|
118
|
+
end: findBlockEnd(code, brace),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
return fns;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* `use` declarations, excluding the prelude-adjacent std paths.
|
|
125
|
+
*
|
|
126
|
+
* `std`, `core` and `alloc` ship with the language, so counting them would make
|
|
127
|
+
* the import count meaningless - the same reasoning that excludes `java.*` and
|
|
128
|
+
* `System.*`. `crate::`, `self::` and `super::` are internal, not dependencies.
|
|
129
|
+
*/
|
|
130
|
+
/** Splits a brace-group body on commas that are not inside a nested group. */
|
|
131
|
+
function splitTopLevel(body) {
|
|
132
|
+
const parts = [];
|
|
133
|
+
let depth = 0;
|
|
134
|
+
let current = '';
|
|
135
|
+
for (const ch of body) {
|
|
136
|
+
if (ch === '{')
|
|
137
|
+
depth++;
|
|
138
|
+
else if (ch === '}')
|
|
139
|
+
depth--;
|
|
140
|
+
if (ch === ',' && depth === 0) {
|
|
141
|
+
parts.push(current);
|
|
142
|
+
current = '';
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
current += ch;
|
|
146
|
+
}
|
|
147
|
+
parts.push(current);
|
|
148
|
+
return parts;
|
|
149
|
+
}
|
|
150
|
+
/** `button::{Button, ButtonVariants}` under a prefix, as one entry per leaf. */
|
|
151
|
+
function expandNestedGroup(prefix, piece, line) {
|
|
152
|
+
const inner = /^(.*?)\{(.+)\}$/.exec(piece);
|
|
153
|
+
if (!inner)
|
|
154
|
+
return [];
|
|
155
|
+
const innerPrefix = prefix + inner[1];
|
|
156
|
+
const out = [];
|
|
157
|
+
for (const nested of splitTopLevel(inner[2])) {
|
|
158
|
+
const trimmed = nested.trim();
|
|
159
|
+
if (trimmed === '' || trimmed === 'self')
|
|
160
|
+
continue;
|
|
161
|
+
if (trimmed.includes('{')) {
|
|
162
|
+
for (const deeper of expandNestedGroup(innerPrefix, trimmed, line))
|
|
163
|
+
out.push(deeper);
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
166
|
+
const leaf = trimmed.split(' as ').pop()?.trim() ?? '';
|
|
167
|
+
if (leaf === '' || leaf === 'self')
|
|
168
|
+
continue;
|
|
169
|
+
out.push({ name: innerPrefix + trimmed, line, leaf: leaf.replace(/^.*::/, ''), isGlob: leaf === '*' });
|
|
170
|
+
}
|
|
171
|
+
return out;
|
|
172
|
+
}
|
|
173
|
+
function extractRustUses(source) {
|
|
174
|
+
const code = (0, lexer_1.stripRustComments)(source);
|
|
175
|
+
const out = [];
|
|
176
|
+
// `[ \t]*` rather than `\s*` for the indentation - see the note on the Java
|
|
177
|
+
// import pattern. `\s` matches newlines, so under /m this anchors at every line
|
|
178
|
+
// start and backtracks across the whole file: the same defect class as the
|
|
179
|
+
// `METHOD_RE` quadratic recorded in SECURITY.md 1.4.
|
|
180
|
+
const re = /^[ \t]*(?:pub[ \t]+)?use[ \t]+([^;]+);/gm;
|
|
181
|
+
let match;
|
|
182
|
+
while ((match = re.exec(code)) !== null) {
|
|
183
|
+
const line = (0, lines_1.lineOf)(code, match.index);
|
|
184
|
+
const body = match[1].replace(/\s+/g, ' ').trim();
|
|
185
|
+
// A brace group imports several leaves from one path: use std::io::{Read, Write}
|
|
186
|
+
const group = /^(.*?)\{(.+)\}$/.exec(body);
|
|
187
|
+
if (group) {
|
|
188
|
+
const prefix = group[1];
|
|
189
|
+
// Split on TOP-LEVEL commas only. Rust nests groups freely, and
|
|
190
|
+
// `use gpui_component::{button::{Button, ButtonVariants}, Sizable};` split on
|
|
191
|
+
// every comma produced the leaf names `button::{Button`, `ButtonVariants}`
|
|
192
|
+
// and `Sizable` - two of them carrying a brace, which then matched nothing in
|
|
193
|
+
// the body and were reported as unused. Measured on the real gpui-component
|
|
194
|
+
// repo 2026-08-17: brace-bearing garbage names accounted for a large share of
|
|
195
|
+
// 2,037 unused-import findings across 471 files.
|
|
196
|
+
for (const piece of splitTopLevel(group[2])) {
|
|
197
|
+
const trimmed = piece.trim();
|
|
198
|
+
if (trimmed === '' || trimmed === 'self')
|
|
199
|
+
continue;
|
|
200
|
+
// A nested group contributes its own leaves rather than one mangled name.
|
|
201
|
+
if (trimmed.includes('{')) {
|
|
202
|
+
for (const nested of expandNestedGroup(prefix, trimmed, line))
|
|
203
|
+
out.push(nested);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
const leaf = trimmed.split(' as ').pop()?.trim() ?? '';
|
|
207
|
+
if (leaf === '' || leaf === 'self')
|
|
208
|
+
continue;
|
|
209
|
+
out.push({ name: prefix + trimmed, line, leaf: leaf.replace(/^.*::/, ''), isGlob: leaf === '*' });
|
|
210
|
+
}
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
const leaf = body.split(' as ').pop()?.trim().split('::').pop() ?? '';
|
|
214
|
+
out.push({ name: body, line, leaf, isGlob: body.endsWith('::*') });
|
|
215
|
+
}
|
|
216
|
+
return out;
|
|
217
|
+
}
|
|
218
|
+
function thirdPartyUses(uses) {
|
|
219
|
+
return uses
|
|
220
|
+
.filter(entry => !/^(?:std|core|alloc|crate|self|super)\b/.test(entry.name.trim()))
|
|
221
|
+
.map(entry => entry.name.trim());
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* UNUSED IMPORTS ARE DELIBERATELY NOT REPORTED FOR RUST, the same call Ruby and C#
|
|
225
|
+
* already make, and for the same underlying reason: the verdict cannot be stood
|
|
226
|
+
* behind.
|
|
227
|
+
*
|
|
228
|
+
* Rust's blocker is the TRAIT. You import a trait so its methods become callable,
|
|
229
|
+
* and then you never write its name again:
|
|
230
|
+
*
|
|
231
|
+
* use gpui::Styled; // required for `.bg(...)` to compile
|
|
232
|
+
* div().bg(red()) // `Styled` appears nowhere
|
|
233
|
+
*
|
|
234
|
+
* A text search cannot see that usage, and rustc does not warn about it, because
|
|
235
|
+
* the import is correct and genuinely used. Measured on the real gpui-component
|
|
236
|
+
* repository 2026-08-17: 1,411 findings across 471 files, roughly three per file,
|
|
237
|
+
* and the top of the list was entirely traits - `ParentElement` 78 times, `Styled`
|
|
238
|
+
* 75, `AppContext` 69, `InteractiveElement` 67, `StyledExt` 56, `FluentBuilder` 38.
|
|
239
|
+
* Every one correct code. Resolving them needs the dependency's own source, which
|
|
240
|
+
* is well beyond a regex analyser.
|
|
241
|
+
*
|
|
242
|
+
* That is not a tuning problem, so the check is removed rather than narrowed. A
|
|
243
|
+
* rule that is wrong three times per file does not get trusted less - it gets the
|
|
244
|
+
* whole tool switched off.
|
|
245
|
+
*
|
|
246
|
+
* JAVA IS THE OPPOSITE CASE and keeps its check: an import there is a compile-time
|
|
247
|
+
* type alias, there is no trait-method equivalent, javac itself warns, and the same
|
|
248
|
+
* measurement on Elasticsearch gave 25 findings per 1,000 files.
|
|
249
|
+
*
|
|
250
|
+
* `extractRustUses` is still used, and its nested-group parsing still matters: it
|
|
251
|
+
* feeds the third-party import COUNT behind `too-many-imports`, which was also
|
|
252
|
+
* wrong while `use a::{b::{c, d}, e}` was being split on every comma.
|
|
253
|
+
*/
|
|
254
|
+
const RUST_UNUSED_IMPORTS = [];
|
|
255
|
+
function detectRustWarnings(source, fns, imports, config) {
|
|
256
|
+
const warnings = [];
|
|
257
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
258
|
+
const lines = source.split(String.fromCharCode(10));
|
|
259
|
+
// Severity is overridable per rule, the same as every other language.
|
|
260
|
+
const severity = (type, fallback) => config.severityOverrides[type] ?? fallback;
|
|
261
|
+
const warningThreshold = Math.round(config.fileLengthThreshold * 2 / 3);
|
|
262
|
+
if (lines.length > config.fileLengthThreshold) {
|
|
263
|
+
warnings.push({ type: 'file-too-long', message: `File is ${lines.length} lines (>${config.fileLengthThreshold})`, severity: severity('file-too-long', 'error'), line: 1 });
|
|
264
|
+
}
|
|
265
|
+
else if (lines.length > warningThreshold) {
|
|
266
|
+
warnings.push({ type: 'file-too-long', message: `File is ${lines.length} lines (>${warningThreshold})`, severity: severity('file-too-long', 'warning'), line: 1 });
|
|
267
|
+
}
|
|
268
|
+
for (const item of fns) {
|
|
269
|
+
const span = (0, lines_1.lineOf)(code, item.end) - item.line + 1;
|
|
270
|
+
const errorThreshold = config.functionLengthThreshold * 2;
|
|
271
|
+
if (span > errorThreshold) {
|
|
272
|
+
warnings.push({ type: 'function-too-long', message: `${item.name} is ~${span} lines (>${errorThreshold})`, severity: severity('function-too-long', 'error'), line: item.line });
|
|
273
|
+
}
|
|
274
|
+
else if (span > config.functionLengthThreshold) {
|
|
275
|
+
warnings.push({ type: 'function-too-long', message: `${item.name} is ~${span} lines (>${config.functionLengthThreshold})`, severity: severity('function-too-long', 'warning'), line: item.line });
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (fns.length > config.maxFunctionsPerFile) {
|
|
279
|
+
warnings.push({ type: 'too-many-functions', message: `${fns.length} functions in one file (>${config.maxFunctionsPerFile})`, severity: severity('too-many-functions', 'warning') });
|
|
280
|
+
}
|
|
281
|
+
if (imports.length > config.maxImportsPerFile) {
|
|
282
|
+
warnings.push({ type: 'too-many-imports', message: `${imports.length} third-party imports (>${config.maxImportsPerFile})`, severity: severity('too-many-imports', 'warning') });
|
|
283
|
+
}
|
|
284
|
+
return warnings;
|
|
285
|
+
}
|
|
286
|
+
function detectRustSmells(source, fns, config, fileIsTest) {
|
|
287
|
+
const smells = emptyRustSmells();
|
|
288
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
289
|
+
const withStrings = (0, lexer_1.stripRustComments)(source);
|
|
290
|
+
const ranges = testRanges(source);
|
|
291
|
+
// A whole test file exempts everything; otherwise only the inline test
|
|
292
|
+
// modules are exempt.
|
|
293
|
+
const exempt = (index) => fileIsTest || inTestRange(ranges, index);
|
|
294
|
+
const pushLines = (re, target, haystack, honourTests,
|
|
295
|
+
// Collapse repeat matches on ONE line into a single finding. Needed where a
|
|
296
|
+
// pattern's alternations can both match the same construct: `use sha1::Sha1`
|
|
297
|
+
// matches `sha1::` AND `\bSha1\b`, so one import was reported twice, which
|
|
298
|
+
// doubled both the smell count and its score penalty. Off by default,
|
|
299
|
+
// because two `.unwrap()` calls on one line really are two findings.
|
|
300
|
+
onePerLine = false) => {
|
|
301
|
+
re.lastIndex = 0;
|
|
302
|
+
const seen = new Set();
|
|
303
|
+
let match;
|
|
304
|
+
while ((match = re.exec(haystack)) !== null) {
|
|
305
|
+
if (honourTests && exempt(match.index))
|
|
306
|
+
continue;
|
|
307
|
+
const line = (0, lines_1.lineOf)(haystack, match.index);
|
|
308
|
+
if (onePerLine) {
|
|
309
|
+
if (seen.has(line))
|
|
310
|
+
continue;
|
|
311
|
+
seen.add(line);
|
|
312
|
+
}
|
|
313
|
+
target.push({ line });
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
pushLines(/\b(?:println!|eprintln!|print!|eprint!|dbg!)\s*\(/g, smells.consoleLogs, code, true);
|
|
317
|
+
const todoRe = /\/\/+\s*(TODO|FIXME|HACK|XXX)\b[:\s]*(.*)/gi;
|
|
318
|
+
let todo;
|
|
319
|
+
while ((todo = todoRe.exec(source)) !== null) {
|
|
320
|
+
smells.todos.push({ text: `${todo[1]}: ${todo[2].trim()}`.trim(), line: (0, lines_1.lineOf)(source, todo.index) });
|
|
321
|
+
}
|
|
322
|
+
for (const fn of fns) {
|
|
323
|
+
if (fn.paramCount > config.maxParameterCount) {
|
|
324
|
+
smells.longParameterLists.push({ name: fn.name, paramCount: fn.paramCount, line: fn.line });
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
let deepest = 0;
|
|
328
|
+
for (const fn of fns) {
|
|
329
|
+
if (exempt(fn.start))
|
|
330
|
+
continue;
|
|
331
|
+
let depth = 0;
|
|
332
|
+
let peak = 0;
|
|
333
|
+
for (let i = fn.start; i <= fn.end && i < code.length; i++) {
|
|
334
|
+
if (code[i] === '{') {
|
|
335
|
+
depth++;
|
|
336
|
+
peak = Math.max(peak, depth);
|
|
337
|
+
}
|
|
338
|
+
else if (code[i] === '}')
|
|
339
|
+
depth--;
|
|
340
|
+
}
|
|
341
|
+
deepest = Math.max(deepest, Math.max(0, peak - 1));
|
|
342
|
+
}
|
|
343
|
+
smells.deepNesting = deepest;
|
|
344
|
+
const magicRe = /(?<![\w.])(-?\d{2,})(?:_[iu](?:8|16|32|64|size))?(?![\w.])/g;
|
|
345
|
+
const codeLines = code.split('\n');
|
|
346
|
+
let magic;
|
|
347
|
+
while ((magic = magicRe.exec(code)) !== null) {
|
|
348
|
+
if (exempt(magic.index))
|
|
349
|
+
continue;
|
|
350
|
+
const value = magic[1];
|
|
351
|
+
if (['0', '1', '-1', '100', '1000'].includes(value))
|
|
352
|
+
continue;
|
|
353
|
+
const magicLine = (0, lines_1.lineOf)(code, magic.index);
|
|
354
|
+
// A NAMED constant is not a magic number - naming it is the fix the rule
|
|
355
|
+
// asks for. C# has exempted this since it shipped; Rust was missed, and the
|
|
356
|
+
// benchmark's negative fixture is what surfaced it.
|
|
357
|
+
if (RUST_MAGIC_NUMBER_EXEMPT_RE.test(codeLines[magicLine - 1] ?? ''))
|
|
358
|
+
continue;
|
|
359
|
+
smells.magicNumbers.push({ value, line: magicLine });
|
|
360
|
+
}
|
|
361
|
+
if (config.enableSecuritySmells) {
|
|
362
|
+
// NOTE: `unwrap`/`expect` and `panic!` are NOT here any more. They were
|
|
363
|
+
// pushed into `evalUsage`, which reaches the user labelled "eval() / exec()
|
|
364
|
+
// usage - arbitrary code execution risk". That is what every other language
|
|
365
|
+
// puts there - Python `exec()`, Ruby `Kernel.eval` - and an `unwrap` is
|
|
366
|
+
// nothing of the kind. They are now `unwrap-abuse` and `explicit-panic`,
|
|
367
|
+
// emitted as warnings by detectRustPanicRules so they carry their own name,
|
|
368
|
+
// their own severity override, and their own iris-ignore id.
|
|
369
|
+
pushLines(/\bformat!\s*\(\s*"[^"]*(?:SELECT|INSERT|UPDATE|DELETE)[^"]*"\s*,/gi, smells.sqlConcatenation, withStrings, true);
|
|
370
|
+
pushLines(/\brand::random\s*\(|\bthread_rng\s*\(/g, smells.insecureRandom, code, true);
|
|
371
|
+
pushLines(/\bMd5\b|\bSha1\b|\bmd5::|sha1::/g, smells.weakHashing, code, true, true);
|
|
372
|
+
pushLines(/\bdanger_accept_invalid_certs\s*\(\s*true\s*\)|\bdanger_accept_invalid_hostnames\s*\(\s*true\s*\)/g, smells.disabledTlsVerification, code, true);
|
|
373
|
+
if (!fileIsTest) {
|
|
374
|
+
pushLines(/(?:https?:\/\/)?(?:localhost|127\.0\.0\.1)(?::\d+)?/g, smells.hardcodedLocalhost, withStrings, true);
|
|
375
|
+
pushLines(/\b(?:debug|dev_mode)\s*[:=]\s*true\b/gi, smells.debugFlagsEnabled, withStrings, true);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
return smells;
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* The two Rust panic rules, as first-class warnings.
|
|
382
|
+
*
|
|
383
|
+
* Both were originally pushed into `codeSmells.evalUsage`, which was expedient
|
|
384
|
+
* and wrong: that array's user-facing label is "eval() / exec() usage -
|
|
385
|
+
* arbitrary code execution risk", so the single most common Rust finding
|
|
386
|
+
* arrived under a heading describing a different class of defect entirely.
|
|
387
|
+
* Giving them real ids also gives them the three things a shared array cannot:
|
|
388
|
+
* a `severityOverrides` entry, an `iris-ignore: unwrap-abuse` directive, and
|
|
389
|
+
* their own group in the Problems tab.
|
|
390
|
+
*
|
|
391
|
+
* They are SEPARATE rules because the fixes differ. An `unwrap` is an unhandled
|
|
392
|
+
* error path - the fix is `?` or a match. A `panic!`/`todo!`/`unimplemented!` is
|
|
393
|
+
* deliberate abort - the fix is to return a Result, or to finish the function.
|
|
394
|
+
*
|
|
395
|
+
* Both honour the inline test ranges, which is the whole reason `testRanges`
|
|
396
|
+
* exists: `#[cfg(test)]` code is full of `unwrap` by design, and a file-level
|
|
397
|
+
* exemption would either spare the production half too or spare nothing.
|
|
398
|
+
*/
|
|
399
|
+
function detectRustPanicRules(source, config, fileIsTest) {
|
|
400
|
+
if (!config.enableSecuritySmells)
|
|
401
|
+
return [];
|
|
402
|
+
const warnings = [];
|
|
403
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
404
|
+
const ranges = testRanges(source);
|
|
405
|
+
const severity = (type, fallback) => config.severityOverrides[type] ?? fallback;
|
|
406
|
+
const scan = (re, type, message, fallback) => {
|
|
407
|
+
re.lastIndex = 0;
|
|
408
|
+
let match;
|
|
409
|
+
while ((match = re.exec(code)) !== null) {
|
|
410
|
+
if (fileIsTest || inTestRange(ranges, match.index))
|
|
411
|
+
continue;
|
|
412
|
+
warnings.push({ type, message, severity: severity(type, fallback), line: (0, lines_1.lineOf)(code, match.index) });
|
|
413
|
+
}
|
|
414
|
+
};
|
|
415
|
+
scan(/\.\s*(?:unwrap|expect)\s*\(/g, 'unwrap-abuse', 'unwrap/expect panics on the error case; propagate with ? or match instead', 'warning');
|
|
416
|
+
scan(/\bpanic!\s*\(|\btodo!\s*\(|\bunimplemented!\s*\(/g, 'explicit-panic', 'Explicit panic aborts the process; return a Result so callers can recover', 'warning');
|
|
417
|
+
return warnings;
|
|
418
|
+
}
|
|
419
|
+
/** `unsafe` blocks with no safety comment above them. */
|
|
420
|
+
function unsafeWithoutSafetyComment(source) {
|
|
421
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
422
|
+
const lines = source.split('\n');
|
|
423
|
+
let count = 0;
|
|
424
|
+
const re = /\bunsafe\s*\{/g;
|
|
425
|
+
let match;
|
|
426
|
+
while ((match = re.exec(code)) !== null) {
|
|
427
|
+
const line = (0, lines_1.lineOf)(code, match.index);
|
|
428
|
+
const preceding = lines.slice(Math.max(0, line - 4), line - 1).join('\n');
|
|
429
|
+
if (!/SAFETY\s*:/i.test(preceding))
|
|
430
|
+
count++;
|
|
431
|
+
}
|
|
432
|
+
return count;
|
|
433
|
+
}
|
|
434
|
+
function scoreRustComplexity(source, codeLineCount, fns, uses) {
|
|
435
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
436
|
+
let score = 1;
|
|
437
|
+
const branches = (code.match(/\b(?:if|for|while|match|loop)\b|&&|\|\|/g) ?? []).length;
|
|
438
|
+
const density = codeLineCount > 0 ? fns.length / (codeLineCount / 50) : 0;
|
|
439
|
+
score += Math.min(3, Math.floor(density));
|
|
440
|
+
score += Math.min(3, Math.floor(branches / 10));
|
|
441
|
+
score += Math.min(2, Math.floor(uses.length / 12));
|
|
442
|
+
score += Math.min(1, unsafeWithoutSafetyComment(source));
|
|
443
|
+
return Math.max(1, Math.min(10, score));
|
|
444
|
+
}
|
|
445
|
+
/**
|
|
446
|
+
* Drops secrets that live inside an inline `#[cfg(test)]` module.
|
|
447
|
+
*
|
|
448
|
+
* `detectHardcodedSecrets` is shared by every language and knows only
|
|
449
|
+
* `isTestFile(filePath)`, which is a FILE-level question. That is enough
|
|
450
|
+
* everywhere else, because every other supported language puts tests in
|
|
451
|
+
* separate files - but it is exactly the assumption Rust breaks, and the reason
|
|
452
|
+
* `testRanges` exists in the first place.
|
|
453
|
+
*
|
|
454
|
+
* Without this, a fixture credential in a `#[cfg(test)] mod tests` block is
|
|
455
|
+
* reported as a production secret: the heaviest finding Iris emits at 10 points,
|
|
456
|
+
* on the file population most likely to be well tested. Someone acting on it
|
|
457
|
+
* would delete a test fixture to fix a leak that was never there. Found
|
|
458
|
+
* 2026-08-16 by running the Rust testbed, after the range exemption had already
|
|
459
|
+
* been wired through unwrap, panic, console output and magic numbers - secrets
|
|
460
|
+
* were the one path that never got it.
|
|
461
|
+
*
|
|
462
|
+
* Matching is by LINE because a HardcodedSecret carries a line, not an offset;
|
|
463
|
+
* the ranges are character offsets, so they are converted once here.
|
|
464
|
+
*/
|
|
465
|
+
function filterTestRangeSecrets(secrets, source, fileIsTest) {
|
|
466
|
+
// A whole test file is already handled by the shared detector.
|
|
467
|
+
if (fileIsTest || secrets.length === 0)
|
|
468
|
+
return secrets;
|
|
469
|
+
const ranges = testRanges(source);
|
|
470
|
+
if (ranges.length === 0)
|
|
471
|
+
return secrets;
|
|
472
|
+
const code = (0, lexer_1.rustCodeOnly)(source);
|
|
473
|
+
const lineRanges = ranges.map(range => ({
|
|
474
|
+
start: (0, lines_1.lineOf)(code, range.start),
|
|
475
|
+
end: (0, lines_1.lineOf)(code, range.end),
|
|
476
|
+
}));
|
|
477
|
+
return secrets.filter(secret => !lineRanges.some(range => secret.line >= range.start && secret.line <= range.end));
|
|
478
|
+
}
|
|
479
|
+
function analyseRust(source, config, filePath = '') {
|
|
480
|
+
const lines = source.split('\n');
|
|
481
|
+
const blankLines = lines.filter(line => line.trim() === '' || /^\s*\/\//.test(line)).length;
|
|
482
|
+
const codeLineCount = lines.length - blankLines;
|
|
483
|
+
const allFns = detectRustFns(source);
|
|
484
|
+
const fns = config.ignoreFunctions.length > 0
|
|
485
|
+
? allFns.filter(fn => !config.ignoreFunctions.includes(fn.name))
|
|
486
|
+
: allFns;
|
|
487
|
+
const uses = thirdPartyUses(extractRustUses(source));
|
|
488
|
+
const fileIsTest = (0, guards_1.isTestFile)(filePath) || /(^|[\\/])(tests|benches|examples)[\\/]/.test(filePath);
|
|
489
|
+
const warnings = [
|
|
490
|
+
...detectRustWarnings(source, fns, uses, config),
|
|
491
|
+
...detectRustPanicRules(source, config, fileIsTest),
|
|
492
|
+
];
|
|
493
|
+
const baseSmells = detectRustSmells(source, fns, config, fileIsTest);
|
|
494
|
+
const hardcodedSecrets = filterTestRangeSecrets((0, secrets_1.detectHardcodedSecrets)(source, config, 'rust', filePath), source, fileIsTest);
|
|
495
|
+
const codeSmells = { ...baseSmells, hardcodedSecrets };
|
|
496
|
+
return {
|
|
497
|
+
lineCount: lines.length, blankLines, codeLines: codeLineCount,
|
|
498
|
+
functions: fns.map(({ name, line }) => ({ name, line })),
|
|
499
|
+
thirdPartyImports: uses,
|
|
500
|
+
unusedImports: RUST_UNUSED_IMPORTS,
|
|
501
|
+
complexityScore: scoreRustComplexity(source, codeLineCount, fns, uses),
|
|
502
|
+
warnings, typeScriptMetrics: ZEROED_TS_METRICS, codeSmells,
|
|
503
|
+
healthScore: (0, scoring_1.computeHealthScore)(warnings, ZEROED_TS_METRICS, codeSmells, config),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
//# sourceMappingURL=analyser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"analyser.js","sourceRoot":"","sources":["../../src/rust/analyser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Rust lexical layer, in its own module because TWO callers need it: the
|
|
3
|
+
* Rust analyser (every structural rule) and `detectParseErrorReason` in
|
|
4
|
+
* guards.ts (the delimiter balance check that decides whether a file is
|
|
5
|
+
* analysed at all).
|
|
6
|
+
*
|
|
7
|
+
* That second caller is why this exists before any rule. C# shipped a defect
|
|
8
|
+
* where a verbatim string read as unterminated, every brace after it landed at
|
|
9
|
+
* the wrong depth, and the file came back a parse error with every finding
|
|
10
|
+
* zeroed - and a zeroed file is indistinguishable from a clean one.
|
|
11
|
+
*
|
|
12
|
+
* Both modes are LENGTH- and LINE-PRESERVING, so a finding's offset still maps
|
|
13
|
+
* to its native line with no remapping layer that could drift.
|
|
14
|
+
*
|
|
15
|
+
* THE LIFETIME IS THE RUST-SPECIFIC TRAP, and it is the exact shape that breaks
|
|
16
|
+
* a naive scanner. `&'a str` is a reference with a lifetime, not a char literal:
|
|
17
|
+
* a scanner that treats `'` as opening a character would run to the NEXT
|
|
18
|
+
* apostrophe somewhere further down the file, blanking real code in between.
|
|
19
|
+
* Lifetimes appear in most non-trivial Rust, so this is the common case rather
|
|
20
|
+
* than an edge one.
|
|
21
|
+
*
|
|
22
|
+
* Also handled, each with its own way of breaking a naive scan:
|
|
23
|
+
* - raw strings at any hash depth: `r"..."`, `r#"..."#`, `r##"..."##`, where a
|
|
24
|
+
* `"` inside does NOT close the literal
|
|
25
|
+
* - raw identifiers: `r#type` is an identifier, not a raw string, so `r#` only
|
|
26
|
+
* opens a literal when a quote follows the hashes
|
|
27
|
+
* - byte strings `b"..."` and byte chars `b'x'`, plus `br#"..."#`
|
|
28
|
+
* - NESTED block comments, which Rust allows and C does not. An inner block
|
|
29
|
+
* comment's closer does NOT end the outer one, so a depth counter is the only
|
|
30
|
+
* way to see where the comment really ends. (Writing that construct literally
|
|
31
|
+
* in this very comment ended it early on the first build - the same class of
|
|
32
|
+
* mistake the module exists to prevent.)
|
|
33
|
+
*/
|
|
34
|
+
export declare function transformRust(source: string, blankStrings: boolean): string;
|
|
35
|
+
/** Comments blanked, string contents intact. */
|
|
36
|
+
export declare function stripRustComments(source: string): string;
|
|
37
|
+
/** Comments AND string contents blanked: the input for anything structural. */
|
|
38
|
+
export declare function rustCodeOnly(source: string): string;
|
|
39
|
+
//# sourceMappingURL=lexer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lexer.d.ts","sourceRoot":"","sources":["../../src/rust/lexer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAYH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,GAAG,MAAM,CAwH3E;AAED,gDAAgD;AAChD,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAExD;AAED,+EAA+E;AAC/E,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAEnD"}
|