pi-lens 3.8.37 → 3.8.39
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/CHANGELOG.md +21 -0
- package/README.md +2 -2
- package/banner.png +0 -0
- package/banner.svg +31 -16
- package/clients/cache/rule-cache.ts +2 -1
- package/clients/cache-manager.ts +4 -1
- package/clients/dispatch/fact-scheduler.ts +2 -1
- package/clients/dispatch/fact-store.ts +4 -6
- package/clients/dispatch/integration.ts +2 -5
- package/clients/dispatch/rules/quality-rules.ts +10 -15
- package/clients/dispatch/runners/biome-check.ts +1 -1
- package/clients/dispatch/runners/eslint.ts +1 -1
- package/clients/dispatch/runners/lsp.ts +1 -5
- package/clients/dispatch/runners/psscriptanalyzer.ts +1 -1
- package/clients/dispatch/runners/similarity.ts +1 -4
- package/clients/dispatch/utils/lsp-diagnostics.ts +3 -9
- package/clients/formatters.ts +12 -7
- package/clients/lsp/index.ts +8 -10
- package/clients/lsp/launch.ts +5 -8
- package/clients/lsp/server.ts +1 -1
- package/clients/pipeline.ts +6 -11
- package/clients/read-guard.ts +5 -6
- package/clients/runtime-coordinator.ts +2 -2
- package/clients/runtime-tool-result.ts +1 -3
- package/clients/secrets-scanner.ts +1 -1
- package/clients/session-summary.ts +1 -1
- package/clients/tree-sitter-query-loader.ts +3 -2
- package/commands/booboo.ts +15 -14
- package/index.ts +5 -5
- package/package.json +3 -2
- package/rules/rule-catalog.json +52 -1
- package/rules/tree-sitter-queries/abap/delete-where.yml +46 -0
- package/rules/tree-sitter-queries/c/case-range-multiple-values.yml +65 -0
- package/rules/tree-sitter-queries/c/goto-into-block.yml +72 -0
- package/rules/tree-sitter-queries/c/goto-label-order.yml +65 -0
- package/rules/tree-sitter-queries/cobol/alter-statement.yml +39 -0
- package/rules/tree-sitter-queries/cpp/no-auto-ptr.yml +49 -0
- package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +59 -0
- package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +57 -0
- package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +52 -0
- package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +58 -0
- package/rules/tree-sitter-queries/csharp/async-await-identifiers.yml +50 -0
- package/rules/tree-sitter-queries/csharp/is-with-this.yml +52 -0
- package/rules/tree-sitter-queries/csharp/no-dangerous-get-handle.yml +59 -0
- package/rules/tree-sitter-queries/csharp/no-operator-eq-reference.yml +60 -0
- package/rules/tree-sitter-queries/csharp/no-thread-resume-suspend.yml +60 -0
- package/rules/tree-sitter-queries/css/calc-spacing.yml +50 -0
- package/rules/tree-sitter-queries/java/junit-call-super.yml +63 -0
- package/rules/tree-sitter-queries/java/main-should-not-throw.yml +63 -0
- package/rules/tree-sitter-queries/java/no-clone-override.yml +60 -0
- package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +74 -0
- package/rules/tree-sitter-queries/java/no-exit-methods.yml +50 -0
- package/rules/tree-sitter-queries/java/no-field-shadowing.yml +66 -0
- package/rules/tree-sitter-queries/java/no-future-keywords.yml +49 -0
- package/rules/tree-sitter-queries/java/no-threadgroup.yml +52 -0
- package/rules/tree-sitter-queries/java/no-threads-in-constructors.yml +73 -0
- package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +58 -0
- package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +55 -0
- package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +75 -0
- package/rules/tree-sitter-queries/java/springboot-default-package.yml +69 -0
- package/rules/tree-sitter-queries/java/switch-fall-through.yml +70 -0
- package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +62 -0
- package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +52 -0
- package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +49 -0
- package/rules/tree-sitter-queries/php/no-exit-die.yml +52 -0
- package/rules/tree-sitter-queries/php/this-in-static-context.yml +75 -0
- package/rules/tree-sitter-queries/plsql/delete-update-where.yml +56 -0
- package/rules/tree-sitter-queries/plsql/end-loop-semicolon.yml +51 -0
- package/rules/tree-sitter-queries/plsql/fetch-bulk-collect-limit.yml +47 -0
- package/rules/tree-sitter-queries/plsql/forallsave-exceptions.yml +51 -0
- package/rules/tree-sitter-queries/plsql/no-synchronize.yml +47 -0
- package/rules/tree-sitter-queries/plsql/not-null-initialization.yml +59 -0
- package/rules/tree-sitter-queries/plsql/raise-application-error-codes.yml +50 -0
- package/rules/tree-sitter-queries/python/exit-signature-check.yml +66 -0
- package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +57 -0
- package/rules/tree-sitter-queries/python/iter-return-iterator.yml +59 -0
- package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +67 -0
- package/rules/tree-sitter-queries/python/return-in-generator.yml +58 -0
- package/rules/tree-sitter-queries/python/return-in-init.yml +59 -0
- package/rules/tree-sitter-queries/python/send-file-mimetype.yml +53 -0
- package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +57 -0
- package/tools/lsp-navigation.js +14 -16
- package/tools/lsp-navigation.ts +14 -18
package/commands/booboo.ts
CHANGED
|
@@ -1149,9 +1149,7 @@ export async function handleBooboo(
|
|
|
1149
1149
|
inner.spans?.[0];
|
|
1150
1150
|
if (!span) continue;
|
|
1151
1151
|
const absFile = span.file_name
|
|
1152
|
-
? path.isAbsolute(span.file_name)
|
|
1153
|
-
? span.file_name
|
|
1154
|
-
: path.join(targetPath, span.file_name)
|
|
1152
|
+
? (path.isAbsolute(span.file_name) ? span.file_name : path.join(targetPath, span.file_name))
|
|
1155
1153
|
: targetPath;
|
|
1156
1154
|
issues.push({
|
|
1157
1155
|
file: path.relative(targetPath, absFile),
|
|
@@ -1183,9 +1181,7 @@ export async function handleBooboo(
|
|
|
1183
1181
|
for (const diag of json?.generalDiagnostics ?? []) {
|
|
1184
1182
|
if (!["error", "warning"].includes(diag.severity)) continue;
|
|
1185
1183
|
const absFile = diag.file
|
|
1186
|
-
? path.isAbsolute(diag.file)
|
|
1187
|
-
? diag.file
|
|
1188
|
-
: path.join(targetPath, diag.file)
|
|
1184
|
+
? (path.isAbsolute(diag.file) ? diag.file : path.join(targetPath, diag.file))
|
|
1189
1185
|
: targetPath;
|
|
1190
1186
|
if (shouldIncludeFile(absFile)) {
|
|
1191
1187
|
issues.push({
|
|
@@ -1331,7 +1327,7 @@ export async function handleBooboo(
|
|
|
1331
1327
|
);
|
|
1332
1328
|
const output = (result.stdout || "") + (result.stderr || "");
|
|
1333
1329
|
const csRe =
|
|
1334
|
-
/^([^\s(]+\.cs)\((\d+),(\d+)\):\s+(error|warning)\s+([A-Z]+\d+):\s+([
|
|
1330
|
+
/^([^\s(]+\.cs)\((\d+),(\d+)\):\s+(error|warning)\s+([A-Z]+\d+):\s+([^[]+)/gm;
|
|
1335
1331
|
for (const m of output.matchAll(csRe)) {
|
|
1336
1332
|
const [, file, line, col, sev, code, msg] = m;
|
|
1337
1333
|
const absFile = path.isAbsolute(file)
|
|
@@ -1394,10 +1390,13 @@ export async function handleBooboo(
|
|
|
1394
1390
|
timeout: 60_000,
|
|
1395
1391
|
});
|
|
1396
1392
|
const output = (result.stdout || "") + (result.stderr || "");
|
|
1397
|
-
const
|
|
1398
|
-
|
|
1399
|
-
for (
|
|
1400
|
-
const
|
|
1393
|
+
const gleamLines = output.split("\n");
|
|
1394
|
+
const gleamHeaderRe = /^([^:]+):(\d+):(\d+)[ \t]*(?:error|warning)/;
|
|
1395
|
+
for (let i = 0; i < gleamLines.length; i++) {
|
|
1396
|
+
const m = gleamHeaderRe.exec(gleamLines[i]);
|
|
1397
|
+
if (!m) continue;
|
|
1398
|
+
const [, file, line, col] = m;
|
|
1399
|
+
const msg = gleamLines[i + 1]?.trim() ?? "";
|
|
1401
1400
|
const absFile = path.isAbsolute(file)
|
|
1402
1401
|
? file
|
|
1403
1402
|
: path.join(targetPath, file);
|
|
@@ -1408,7 +1407,7 @@ export async function handleBooboo(
|
|
|
1408
1407
|
col: parseInt(col, 10),
|
|
1409
1408
|
severity: "error",
|
|
1410
1409
|
code: "gleam",
|
|
1411
|
-
message: msg
|
|
1410
|
+
message: msg,
|
|
1412
1411
|
compiler: "gleam check",
|
|
1413
1412
|
});
|
|
1414
1413
|
}
|
|
@@ -1426,8 +1425,10 @@ export async function handleBooboo(
|
|
|
1426
1425
|
timeout: 120_000,
|
|
1427
1426
|
});
|
|
1428
1427
|
const output = (result.stdout || "") + (result.stderr || "");
|
|
1429
|
-
const
|
|
1430
|
-
for (const
|
|
1428
|
+
const zigLineRe = /^([^:]+):(\d+):(\d+):[ \t]*(error|warning|note):[ \t]*(.+)/;
|
|
1429
|
+
for (const zigLine of output.split("\n")) {
|
|
1430
|
+
const m = zigLineRe.exec(zigLine);
|
|
1431
|
+
if (!m) continue;
|
|
1431
1432
|
const [, file, line, col, sev, msg] = m;
|
|
1432
1433
|
const absFile = path.isAbsolute(file)
|
|
1433
1434
|
? file
|
package/index.ts
CHANGED
|
@@ -1148,7 +1148,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1148
1148
|
if (dupeWarnings.length > 0) {
|
|
1149
1149
|
return {
|
|
1150
1150
|
block: true,
|
|
1151
|
-
reason:
|
|
1151
|
+
reason: "🔴 STOP - Redefining existing export(s). Import instead:\n" + dupeWarnings.map((w) => " • " + w).join("\n"),
|
|
1152
1152
|
};
|
|
1153
1153
|
}
|
|
1154
1154
|
|
|
@@ -1321,9 +1321,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
1321
1321
|
// --- Inject turn-end findings into next agent turn ---
|
|
1322
1322
|
// jscpd, madge, and turn-end delta results are cached at turn_end and consumed here
|
|
1323
1323
|
// via the context event, which fires before each provider request.
|
|
1324
|
-
// Important:
|
|
1325
|
-
//
|
|
1326
|
-
//
|
|
1324
|
+
// Important: keep the user's prompt as the trailing message. Some provider bridges
|
|
1325
|
+
// treat the final message as the active user action, so pi-lens context must be
|
|
1326
|
+
// prepended instead of appended.
|
|
1327
1327
|
// biome-ignore lint/suspicious/noExplicitAny: pi.on("context") overload has TS resolution bug
|
|
1328
1328
|
(pi as any).on(
|
|
1329
1329
|
"context",
|
|
@@ -1348,7 +1348,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
1348
1348
|
?.messages ?? [];
|
|
1349
1349
|
|
|
1350
1350
|
return {
|
|
1351
|
-
messages: [...
|
|
1351
|
+
messages: [...injectedMessages, ...existingMessages],
|
|
1352
1352
|
};
|
|
1353
1353
|
} catch (err) {
|
|
1354
1354
|
dbg(`context event error: ${err}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-lens",
|
|
3
|
-
"version": "3.8.
|
|
3
|
+
"version": "3.8.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Real-time code feedback for pi \u2014 LSP, linters, formatters, type-checking, structural analysis & booboo",
|
|
6
6
|
"repository": {
|
|
@@ -55,7 +55,8 @@
|
|
|
55
55
|
"tsconfig.json",
|
|
56
56
|
"README.md",
|
|
57
57
|
"CHANGELOG.md",
|
|
58
|
-
"banner.svg"
|
|
58
|
+
"banner.svg",
|
|
59
|
+
"banner.png"
|
|
59
60
|
],
|
|
60
61
|
"peerDependencies": {
|
|
61
62
|
"@mariozechner/pi-coding-agent": "*"
|
package/rules/rule-catalog.json
CHANGED
|
@@ -59,6 +59,57 @@
|
|
|
59
59
|
{ "rule_id": "missed-concurrency", "engine": "ast-grep", "language": "typescript", "family": "concurrency", "scope": "function", "canonical_concept": "sequential-awaits-parallelizable", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
60
60
|
{ "rule_id": "missed-concurrency-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "sequential-awaits-parallelizable", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
61
61
|
{ "rule_id": "no-await-in-loop", "engine": "ast-grep", "language": "typescript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
62
|
-
{ "rule_id": "no-await-in-loop-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" }
|
|
62
|
+
{ "rule_id": "no-await-in-loop-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
63
|
+
|
|
64
|
+
{ "rule_id": "return-in-init", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "return-in-init", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
65
|
+
{ "rule_id": "yield-return-outside-function", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "file", "canonical_concept": "invalid-statement-context", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
66
|
+
{ "rule_id": "notimplemented-boolean-context", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "deprecated-boolean-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
67
|
+
{ "rule_id": "exit-signature-check", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "context-manager-signature", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
68
|
+
{ "rule_id": "return-in-generator", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "return-in-generator", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
69
|
+
{ "rule_id": "iter-return-iterator", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "iter-protocol-violation", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
70
|
+
{ "rule_id": "switch-non-case-labels", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "switch-label-violation", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
71
|
+
{ "rule_id": "no-clone-override", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "class", "canonical_concept": "clone-override", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
72
|
+
{ "rule_id": "main-should-not-throw", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "main-throws-exception", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
73
|
+
{ "rule_id": "no-threadgroup", "engine": "tree-sitter", "language": "java", "family": "security", "scope": "file", "canonical_concept": "deprecated-api-usage", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
74
|
+
{ "rule_id": "this-in-static-context", "engine": "tree-sitter", "language": "php", "family": "reliability", "scope": "function", "canonical_concept": "this-in-static-context", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
75
|
+
{ "rule_id": "no-exit-die", "engine": "tree-sitter", "language": "php", "family": "reliability", "scope": "function", "canonical_concept": "abrupt-termination", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
76
|
+
{ "rule_id": "case-range-multiple-values", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "case-range-single-value", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
77
|
+
{ "rule_id": "goto-label-order", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "backward-goto", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
78
|
+
{ "rule_id": "goto-into-block", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "goto-into-block", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
79
|
+
{ "rule_id": "no-auto-ptr", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "file", "canonical_concept": "deprecated-auto-ptr", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
80
|
+
{ "rule_id": "no-memset-sensitive-data", "engine": "tree-sitter", "language": "cpp", "family": "security", "scope": "function", "canonical_concept": "insecure-memory-clear", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
81
|
+
{ "rule_id": "no-scoped-lock-without-args", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "scoped-lock-no-mutex", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
82
|
+
{ "rule_id": "no-confused-move-forward", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "move-forward-confusion", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
83
|
+
{ "rule_id": "is-with-this", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "function", "canonical_concept": "is-operator-with-this", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
84
|
+
{ "rule_id": "no-operator-eq-reference", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "class", "canonical_concept": "operator-eq-reference-type", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
85
|
+
{ "rule_id": "no-dangerous-get-handle", "engine": "tree-sitter", "language": "csharp", "family": "reliability", "scope": "function", "canonical_concept": "unsafe-handle-access", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
86
|
+
{ "rule_id": "no-thread-resume-suspend", "engine": "tree-sitter", "language": "csharp", "family": "reliability", "scope": "function", "canonical_concept": "deprecated-thread-api", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
87
|
+
{ "rule_id": "async-await-identifiers", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "file", "canonical_concept": "keyword-as-identifier", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
88
|
+
{ "rule_id": "in-operator-unsupported", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "in-operator-unsupported", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
89
|
+
{ "rule_id": "spring-session-attributes-setcomplete", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "class", "canonical_concept": "session-attributes-cleanup", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
90
|
+
{ "rule_id": "springboot-default-package", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "file", "canonical_concept": "default-package-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
91
|
+
{ "rule_id": "prepared-statement-valid-indices", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "jdbc-invalid-index", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
92
|
+
{ "rule_id": "delete-update-where", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "sql-missing-where", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
93
|
+
{ "rule_id": "fetch-bulk-collect-limit", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "fetch-no-limit", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
94
|
+
{ "rule_id": "prepared-statement-indices", "engine": "tree-sitter", "language": "kotlin", "family": "reliability", "scope": "function", "canonical_concept": "jdbc-invalid-index", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
95
|
+
{ "rule_id": "delete-where", "engine": "tree-sitter", "language": "abap", "family": "reliability", "scope": "function", "canonical_concept": "sql-missing-where", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
96
|
+
{ "rule_id": "alter-statement", "engine": "tree-sitter", "language": "cobol", "family": "maintainability", "scope": "file", "canonical_concept": "alter-statement-usage", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
97
|
+
{ "rule_id": "calc-spacing", "engine": "tree-sitter", "language": "css", "family": "reliability", "scope": "file", "canonical_concept": "calc-spacing-error", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
98
|
+
{ "rule_id": "switch-non-case-labels-js", "engine": "tree-sitter", "language": "javascript", "family": "reliability", "scope": "function", "canonical_concept": "switch-label-violation", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
99
|
+
{ "rule_id": "no-exit-methods", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "abrupt-termination", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
100
|
+
{ "rule_id": "no-threads-in-constructors", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "constructor", "canonical_concept": "thread-in-constructor", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
101
|
+
{ "rule_id": "switch-fall-through", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "switch-fall-through", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
102
|
+
{ "rule_id": "no-wait-notify-on-thread", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "wait-on-thread-instance", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
103
|
+
{ "rule_id": "no-double-checked-locking", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "double-checked-locking", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
104
|
+
{ "rule_id": "no-future-keywords", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "file", "canonical_concept": "future-keyword-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
105
|
+
{ "rule_id": "no-field-shadowing", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "class", "canonical_concept": "field-shadowing", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
106
|
+
{ "rule_id": "junit-call-super", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "missing-super-call", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
107
|
+
{ "rule_id": "forallsave-exceptions", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "forall-no-save-exceptions", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
108
|
+
{ "rule_id": "not-null-initialization", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "not-null-uninitialized", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
109
|
+
{ "rule_id": "end-loop-semicolon", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "missing-semicolon", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
110
|
+
{ "rule_id": "raise-application-error-codes", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "invalid-error-code", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
111
|
+
{ "rule_id": "no-synchronize", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "synchronize-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
112
|
+
{ "rule_id": "send-file-mimetype", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "send-file-missing-mimetype", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
113
|
+
{ "rule_id": "noexcept-functions", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "missing-noexcept", "severity_default": "error", "confidence": "medium", "status": "active" }
|
|
63
114
|
]
|
|
64
115
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# ABAP DELETE Without WHERE
|
|
2
|
+
# Detects DELETE statements without WHERE in ABAP
|
|
3
|
+
id: delete-where
|
|
4
|
+
name: DELETE FROM Should Have WHERE Clause
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: abap
|
|
10
|
+
|
|
11
|
+
message: "DELETE FROM statement should have a WHERE clause"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
DELETE FROM without WHERE deletes ALL rows. Almost always a bug.
|
|
15
|
+
|
|
16
|
+
✅ FIX: Add WHERE clause
|
|
17
|
+
|
|
18
|
+
```abap
|
|
19
|
+
DELETE FROM employees WHERE id = lv_id. " GOOD
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
query: |
|
|
23
|
+
(delete_statement
|
|
24
|
+
(delete) @DELETE
|
|
25
|
+
(from_clause)
|
|
26
|
+
(where_clause)? @WHERE)
|
|
27
|
+
|
|
28
|
+
metavars:
|
|
29
|
+
- DELETE
|
|
30
|
+
- WHERE
|
|
31
|
+
|
|
32
|
+
post_filter: missing_where
|
|
33
|
+
|
|
34
|
+
tags:
|
|
35
|
+
- reliability
|
|
36
|
+
- abap
|
|
37
|
+
- data-loss
|
|
38
|
+
|
|
39
|
+
examples:
|
|
40
|
+
bad: |
|
|
41
|
+
DELETE FROM employees. " BAD
|
|
42
|
+
|
|
43
|
+
good: |
|
|
44
|
+
DELETE FROM employees WHERE id = 123. " GOOD
|
|
45
|
+
|
|
46
|
+
has_fix: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Case Ranges Should Cover Multiple Values
|
|
2
|
+
# Detects case statements with ranges that only cover single values
|
|
3
|
+
id: case-range-multiple-values
|
|
4
|
+
name: Case Ranges Should Cover Multiple Values
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "Case range should cover multiple values"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
GCC case ranges (case 1..5:) should cover multiple values.
|
|
15
|
+
Using ranges for single values is confusing and unnecessary.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Use regular case for single values, ranges for multiple
|
|
18
|
+
|
|
19
|
+
```c
|
|
20
|
+
switch (value) {
|
|
21
|
+
case 1: // Single value - use regular case
|
|
22
|
+
break;
|
|
23
|
+
case 10..20: // Range - multiple values
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
query: |
|
|
29
|
+
(switch_statement
|
|
30
|
+
body: (compound_statement
|
|
31
|
+
(case_statement
|
|
32
|
+
value: (range_expression
|
|
33
|
+
(number_literal) @START
|
|
34
|
+
(number_literal) @END) @RANGE)))
|
|
35
|
+
|
|
36
|
+
metavars:
|
|
37
|
+
- START
|
|
38
|
+
- END
|
|
39
|
+
- RANGE
|
|
40
|
+
|
|
41
|
+
post_filter: case_range_single_value
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- maintainability
|
|
45
|
+
- c
|
|
46
|
+
- gnu
|
|
47
|
+
- switch
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
switch (val) {
|
|
52
|
+
case 5..5: // BAD - range with single value
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
good: |
|
|
57
|
+
switch (val) {
|
|
58
|
+
case 5: // GOOD - single value
|
|
59
|
+
break;
|
|
60
|
+
case 10..20: // GOOD - actual range
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
has_fix: true
|
|
65
|
+
fix_action: simplify_single_case_range
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Goto Into Block
|
|
2
|
+
# Detects goto statements that jump into blocks
|
|
3
|
+
id: goto-into-block
|
|
4
|
+
name: Goto Should Not Jump Into Blocks
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "goto statements should not be used to jump into blocks"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Jumping into a block bypasses variable initialization and
|
|
15
|
+
is undefined behavior. This is a MISRA C requirement.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Jump to the block's beginning or restructure code
|
|
18
|
+
|
|
19
|
+
```c
|
|
20
|
+
void process() {
|
|
21
|
+
if (error) {
|
|
22
|
+
goto cleanup;
|
|
23
|
+
}
|
|
24
|
+
// ... code ...
|
|
25
|
+
cleanup:
|
|
26
|
+
{ // Jump to block start
|
|
27
|
+
free_resources();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
query: |
|
|
33
|
+
(function_definition
|
|
34
|
+
body: (compound_statement
|
|
35
|
+
(goto_statement
|
|
36
|
+
(statement_identifier) @TARGET) @GOTO))
|
|
37
|
+
|
|
38
|
+
metavars:
|
|
39
|
+
- TARGET
|
|
40
|
+
- GOTO
|
|
41
|
+
|
|
42
|
+
post_filter: goto_targets_inner_block
|
|
43
|
+
|
|
44
|
+
tags:
|
|
45
|
+
- maintainability
|
|
46
|
+
- c
|
|
47
|
+
- misra
|
|
48
|
+
- undefined-behavior
|
|
49
|
+
|
|
50
|
+
examples:
|
|
51
|
+
bad: |
|
|
52
|
+
void func() {
|
|
53
|
+
if (cond) {
|
|
54
|
+
goto inside; // BAD - jumps into block
|
|
55
|
+
}
|
|
56
|
+
{
|
|
57
|
+
inside:
|
|
58
|
+
x = 1; // Variable might not be initialized!
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
good: |
|
|
63
|
+
void func() {
|
|
64
|
+
if (cond) {
|
|
65
|
+
needsProcessing = true;
|
|
66
|
+
}
|
|
67
|
+
if (needsProcessing) { // GOOD - restructure
|
|
68
|
+
x = 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
has_fix: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Goto Label Order
|
|
2
|
+
# Detects goto statements that jump to labels declared earlier
|
|
3
|
+
id: goto-label-order
|
|
4
|
+
name: Goto Should Jump to Later Labels
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "goto should jump to labels declared later in the same function"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Goto statements should only jump forward to labels declared later.
|
|
15
|
+
Backward jumps create spaghetti code and are harder to understand.
|
|
16
|
+
This is a MISRA C requirement.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Restructure to use forward jumps only
|
|
19
|
+
|
|
20
|
+
```c
|
|
21
|
+
void process() {
|
|
22
|
+
if (error) {
|
|
23
|
+
goto cleanup; // Forward jump - OK
|
|
24
|
+
}
|
|
25
|
+
// ... code ...
|
|
26
|
+
cleanup:
|
|
27
|
+
free_resources();
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
query: |
|
|
32
|
+
(function_definition
|
|
33
|
+
body: (compound_statement
|
|
34
|
+
(goto_statement
|
|
35
|
+
(statement_identifier) @LABEL) @GOTO))
|
|
36
|
+
|
|
37
|
+
metavars:
|
|
38
|
+
- LABEL
|
|
39
|
+
- GOTO
|
|
40
|
+
|
|
41
|
+
post_filter: goto_jumps_backward
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- maintainability
|
|
45
|
+
- c
|
|
46
|
+
- misra
|
|
47
|
+
- control-flow
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
void func() {
|
|
52
|
+
loop:
|
|
53
|
+
if (done) return;
|
|
54
|
+
process();
|
|
55
|
+
goto loop; // BAD - backward jump
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
good: |
|
|
59
|
+
void func() {
|
|
60
|
+
while (!done) { // GOOD - use loop instead
|
|
61
|
+
process();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
has_fix: false
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# COBOL ALTER Statement
|
|
2
|
+
# Detects ALTER statement usage in COBOL
|
|
3
|
+
id: alter-statement
|
|
4
|
+
name: ALTER Should Not Be Used
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: cobol
|
|
10
|
+
|
|
11
|
+
message: "ALTER should not be used - causes spaghetti code"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
ALTER changes paragraph/section execution flow at runtime.
|
|
15
|
+
This is deprecated and causes unmaintainable spaghetti code.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Restructure to use PERFORM or other control flow
|
|
18
|
+
|
|
19
|
+
query: |
|
|
20
|
+
(alter_statement
|
|
21
|
+
(ALTER) @ALTER)
|
|
22
|
+
|
|
23
|
+
metavars:
|
|
24
|
+
- ALTER
|
|
25
|
+
|
|
26
|
+
tags:
|
|
27
|
+
- maintainability
|
|
28
|
+
- cobol
|
|
29
|
+
- brain-overload
|
|
30
|
+
- deprecated
|
|
31
|
+
|
|
32
|
+
examples:
|
|
33
|
+
bad: |
|
|
34
|
+
ALTER PARA-1 TO PROCEED TO PARA-2. -- BAD
|
|
35
|
+
|
|
36
|
+
good: |
|
|
37
|
+
PERFORM PARA-2. -- GOOD - explicit control flow
|
|
38
|
+
|
|
39
|
+
has_fix: false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# No std::auto_ptr
|
|
2
|
+
# Detects usage of deprecated std::auto_ptr
|
|
3
|
+
id: no-auto-ptr
|
|
4
|
+
name: std::auto_ptr Should Not Be Used
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "std::auto_ptr should not be used — use std::unique_ptr instead"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
std::auto_ptr is deprecated (since C++11) and removed in C++17.
|
|
15
|
+
It has dangerous copy semantics. Use std::unique_ptr instead.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Replace with std::unique_ptr
|
|
18
|
+
|
|
19
|
+
```cpp
|
|
20
|
+
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(); // GOOD
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
query: |
|
|
24
|
+
(template_type
|
|
25
|
+
name: (type_identifier) @NAME (#eq? @NAME "auto_ptr")
|
|
26
|
+
arguments: (template_argument_list) @ARGS)
|
|
27
|
+
((type_identifier) @NAME
|
|
28
|
+
(#eq? @NAME "auto_ptr"))
|
|
29
|
+
|
|
30
|
+
metavars:
|
|
31
|
+
- NAME
|
|
32
|
+
- ARGS
|
|
33
|
+
|
|
34
|
+
tags:
|
|
35
|
+
- reliability
|
|
36
|
+
- cpp
|
|
37
|
+
- deprecated
|
|
38
|
+
- since-cpp11
|
|
39
|
+
- removed-cpp17
|
|
40
|
+
|
|
41
|
+
examples:
|
|
42
|
+
bad: |
|
|
43
|
+
std::auto_ptr<MyClass> ptr(new MyClass()); // BAD - deprecated
|
|
44
|
+
|
|
45
|
+
good: |
|
|
46
|
+
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(); // GOOD
|
|
47
|
+
|
|
48
|
+
has_fix: true
|
|
49
|
+
fix_action: replace_auto_with_unique_ptr
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# No Confused std::move/std::forward
|
|
2
|
+
# Detects potential confusion between std::move and std::forward
|
|
3
|
+
id: no-confused-move-forward
|
|
4
|
+
name: std::move and std::forward Should Not Be Confused
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "std::move and std::forward should not be confused"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
std::move unconditionally casts to rvalue, while std::forward
|
|
15
|
+
conditionally casts based on template parameter. Using the wrong
|
|
16
|
+
one can lead to subtle bugs and unexpected copies/moves.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Use std::move for known objects, std::forward for templates
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
template<typename T>
|
|
22
|
+
void process(T&& t) {
|
|
23
|
+
other(std::forward<T>(t)); // Correct - preserve value category
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
query: |
|
|
28
|
+
(call_expression
|
|
29
|
+
function: (qualified_identifier
|
|
30
|
+
name: (identifier) @FUNC
|
|
31
|
+
(#match? @FUNC "^(move|forward)$"))
|
|
32
|
+
arguments: (argument_list) @ARGS)
|
|
33
|
+
|
|
34
|
+
post_filter: confused_move_forward
|
|
35
|
+
|
|
36
|
+
metavars:
|
|
37
|
+
- FUNC
|
|
38
|
+
- ARGS
|
|
39
|
+
|
|
40
|
+
tags:
|
|
41
|
+
- reliability
|
|
42
|
+
- cpp
|
|
43
|
+
- move-semantics
|
|
44
|
+
- cppcoreguidelines
|
|
45
|
+
|
|
46
|
+
examples:
|
|
47
|
+
bad: |
|
|
48
|
+
template<typename T>
|
|
49
|
+
void wrapper(T&& t) {
|
|
50
|
+
return foo(std::move(t)); // BAD - breaks perfect forwarding
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
good: |
|
|
54
|
+
template<typename T>
|
|
55
|
+
void wrapper(T&& t) {
|
|
56
|
+
return foo(std::forward<T>(t)); // GOOD - preserves category
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
has_fix: false
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# No Memset For Sensitive Data
|
|
2
|
+
# Detects memset used to clear sensitive data
|
|
3
|
+
id: no-memset-sensitive-data
|
|
4
|
+
name: memset Should Not Be Used to Delete Sensitive Data
|
|
5
|
+
severity: error
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: security
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "memset should not be used to delete sensitive data — use SecureZeroMemory or explicit_bzero"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
memset can be optimized away by compilers, leaving sensitive data
|
|
15
|
+
in memory. Use SecureZeroMemory (Windows), explicit_bzero (Linux),
|
|
16
|
+
or std::fill with volatile for clearing passwords/keys.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Use secure memory clearing functions
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
#ifdef _WIN32
|
|
22
|
+
SecureZeroMemory(password, sizeof(password));
|
|
23
|
+
#else
|
|
24
|
+
explicit_bzero(password, sizeof(password));
|
|
25
|
+
#endif
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
query: |
|
|
29
|
+
(call_expression
|
|
30
|
+
function: (identifier) @FUNC (#eq? @FUNC "memset")
|
|
31
|
+
arguments: (argument_list) @ARGS)
|
|
32
|
+
|
|
33
|
+
metavars:
|
|
34
|
+
- FUNC
|
|
35
|
+
- ARGS
|
|
36
|
+
|
|
37
|
+
post_filter: memset_for_sensitive_data
|
|
38
|
+
|
|
39
|
+
tags:
|
|
40
|
+
- security
|
|
41
|
+
- cpp
|
|
42
|
+
- cwe
|
|
43
|
+
- cryptography
|
|
44
|
+
- memory
|
|
45
|
+
|
|
46
|
+
examples:
|
|
47
|
+
bad: |
|
|
48
|
+
char password[32];
|
|
49
|
+
// ... use password ...
|
|
50
|
+
memset(password, 0, sizeof(password)); // BAD - may be optimized away!
|
|
51
|
+
|
|
52
|
+
good: |
|
|
53
|
+
char password[32];
|
|
54
|
+
// ... use password ...
|
|
55
|
+
explicit_bzero(password, sizeof(password)); // GOOD - guaranteed clear
|
|
56
|
+
|
|
57
|
+
has_fix: false
|